<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Model Deployment | Ziyang Lin</title><link>https://ziyanglin.netlify.app/en/tags/model-deployment/</link><atom:link href="https://ziyanglin.netlify.app/en/tags/model-deployment/index.xml" rel="self" type="application/rss+xml"/><description>Model Deployment</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><lastBuildDate>Fri, 27 Jun 2025 03:00:00 +0000</lastBuildDate><image><url>https://ziyanglin.netlify.app/img/icon-192.png</url><title>Model Deployment</title><link>https://ziyanglin.netlify.app/en/tags/model-deployment/</link></image><item><title>LLM Hyperparameter Tuning Guide: A Comprehensive Analysis from Generation to Deployment</title><link>https://ziyanglin.netlify.app/en/post/llm-hyperparameters-documentation/</link><pubDate>Fri, 27 Jun 2025 03:00:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/en/post/llm-hyperparameters-documentation/</guid><description>&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;h2 id="span-stylefontsize-09embehind-the-powerful-capabilities-of-large-language-models-llms-is-a-series-of-complex-hyperparameters-working-silently-whether-youre-deploying-a-local-inference-service-like-vllm-or-calling-openais-api-precisely-tuning-these-parameters-is-crucial-for-achieving-ideal-performance-cost-and-output-quality-this-document-provides-a-detailed-analysis-of-two-key-categories-of-hyperparameters-generation-sampling-parameters-and-deployment-serving-parameters-helping-you-fully-master-their-functions-values-impacts-and-best-practices-across-different-scenariosspan">&lt;span style="font-size: 0.9em;">Behind the powerful capabilities of large language models (LLMs) is a series of complex hyperparameters working silently. Whether you're deploying a local inference service like vLLM or calling OpenAI's API, precisely tuning these parameters is crucial for achieving ideal performance, cost, and output quality. This document provides a detailed analysis of two key categories of hyperparameters: &lt;strong>Generation (Sampling) Parameters&lt;/strong> and &lt;strong>Deployment (Serving) Parameters&lt;/strong>, helping you fully master their functions, values, impacts, and best practices across different scenarios.&lt;/span>&lt;/h2>
&lt;h3 id="part-1-generation-sampling-parameters--controlling-model-creativity-and-determinism">Part 1: Generation (Sampling) Parameters — Controlling Model Creativity and Determinism&lt;/h3>
&lt;p>Generation parameters directly control the model's behavior when generating the next token. They primarily revolve around a core question: how to select from thousands of possible next words in the probability distribution provided by the model.&lt;/p>
&lt;h3 id="1-temperature">1. &lt;code>temperature&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Controls the randomness of generated text. Higher &lt;code>temperature&lt;/code> increases randomness, making responses more creative and diverse; lower &lt;code>temperature&lt;/code> decreases randomness, making responses more deterministic and conservative.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong>
When generating the next token, the model calculates &lt;code>logits&lt;/code> (raw, unnormalized prediction scores) for all words in the vocabulary. Typically, we use the &lt;code>Softmax&lt;/code> function to convert these &lt;code>logits&lt;/code> into a probability distribution. The &lt;code>temperature&lt;/code> parameter is introduced before the &lt;code>Softmax&lt;/code> calculation, &amp;ldquo;smoothing&amp;rdquo; or &amp;ldquo;sharpening&amp;rdquo; this probability distribution.&lt;/p>
&lt;p>The standard Softmax formula is: &lt;code>P(i) = exp(logit_i) / Σ_j(exp(logit_j))&lt;/code>&lt;/p>
&lt;p>With &lt;code>temperature&lt;/code> (T) introduced, the formula becomes: &lt;code>P(i) = exp(logit_i / T) / Σ_j(exp(logit_j / T))&lt;/code>&lt;/p>
&lt;ul>
&lt;li>When &lt;code>T&lt;/code> -&amp;gt; 0, the differences in &lt;code>logit_i / T&lt;/code> become dramatically amplified. The token with the highest logit approaches a probability of 1, while all other tokens approach 0. This causes the model to almost always choose the most likely word, behaving very deterministically and &amp;ldquo;greedily.&amp;rdquo;&lt;/li>
&lt;li>When &lt;code>T&lt;/code> = 1, the formula reverts to standard Softmax, and the model behaves in its &amp;ldquo;original&amp;rdquo; state.&lt;/li>
&lt;li>When &lt;code>T&lt;/code> &amp;gt; 1, the differences in &lt;code>logit_i / T&lt;/code> are reduced. Tokens with originally lower probabilities get boosted, making the entire probability distribution &amp;ldquo;flatter.&amp;rdquo; This increases the chance of selecting less common words, introducing more randomness and creativity.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>[0.0, 2.0]&lt;/code> (theoretically can be higher, but OpenAI API typically limits to 2.0).&lt;/li>
&lt;li>&lt;strong>&lt;code>temperature&lt;/code> = 0.0:&lt;/strong> Suitable for scenarios requiring deterministic, reproducible, and highly accurate outputs. Examples: code generation, factual Q&amp;amp;A, text classification, data extraction. With identical inputs, outputs will be almost identical (unless the model itself is updated).&lt;/li>
&lt;li>&lt;strong>Low &lt;code>temperature&lt;/code> (e.g., &lt;code>0.1&lt;/code> - &lt;code>0.4&lt;/code>):&lt;/strong> Suitable for semi-creative tasks requiring rigor and fidelity to source material. Examples: article summarization, translation, customer service bots. Outputs will vary slightly but remain faithful to core content.&lt;/li>
&lt;li>&lt;strong>Medium &lt;code>temperature&lt;/code> (e.g., &lt;code>0.5&lt;/code> - &lt;code>0.8&lt;/code>):&lt;/strong> A good balance between creativity and consistency, recommended as the default for most applications. Examples: writing emails, marketing copy, brainstorming.&lt;/li>
&lt;li>&lt;strong>High &lt;code>temperature&lt;/code> (e.g., &lt;code>0.9&lt;/code> - &lt;code>1.5&lt;/code>):&lt;/strong> Suitable for highly creative tasks. Examples: poetry writing, story creation, dialogue script generation. Outputs will be very diverse and sometimes surprising, but may occasionally produce meaningless or incoherent content.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Note:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>It's generally not recommended to modify both &lt;code>temperature&lt;/code> and &lt;code>top_p&lt;/code> simultaneously; it's better to adjust just one. OpenAI's documentation explicitly states that modifying only one is typically advised.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="2-topp-nucleus-sampling">2. &lt;code>top_p&lt;/code> (Nucleus Sampling)&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Controls generation diversity by dynamically determining the sampling pool size through a cumulative probability threshold (&lt;code>p&lt;/code>) of the highest probability tokens.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong>
&lt;code>top_p&lt;/code> is a more intelligent sampling strategy than &lt;code>temperature&lt;/code>, also known as &lt;strong>Nucleus Sampling&lt;/strong>. Instead of adjusting all token probabilities, it directly defines a &amp;ldquo;core&amp;rdquo; candidate set.&lt;/p>
&lt;p>The specific steps are as follows:&lt;/p>
&lt;ol>
&lt;li>The model calculates the probability distribution for all candidate tokens.&lt;/li>
&lt;li>All tokens are sorted by probability from highest to lowest.&lt;/li>
&lt;li>Starting from the highest probability token, their probabilities are cumulatively added until this sum exceeds the set &lt;code>top_p&lt;/code> threshold.&lt;/li>
&lt;li>All tokens included in this cumulative sum form the &amp;ldquo;nucleus&amp;rdquo; for sampling.&lt;/li>
&lt;li>The model will only sample from this nucleus (typically renormalizing their probabilities), and all other tokens are ignored.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Example:&lt;/strong> Assume &lt;code>top_p&lt;/code> = &lt;code>0.9&lt;/code>.&lt;/p>
&lt;ul>
&lt;li>If the highest probability token &amp;ldquo;the&amp;rdquo; has a probability of &lt;code>0.95&lt;/code>, then the nucleus will contain only &amp;ldquo;the&amp;rdquo;, and the model will choose it 100%.&lt;/li>
&lt;li>If &amp;ldquo;the&amp;rdquo; has a probability of &lt;code>0.5&lt;/code>, &amp;ldquo;a&amp;rdquo; has &lt;code>0.3&lt;/code>, and &amp;ldquo;an&amp;rdquo; has &lt;code>0.1&lt;/code>, then the cumulative probability of these three words is &lt;code>0.9&lt;/code>. The nucleus will contain {&amp;ldquo;the&amp;rdquo;, &amp;ldquo;a&amp;rdquo;, &amp;ldquo;an&amp;rdquo;}. The model will sample from these three words according to their (renormalized) probabilities.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>(0.0, 1.0]&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>top_p&lt;/code> = 1.0:&lt;/strong> Means the model considers all tokens without any truncation (equivalent to no &lt;code>top_p&lt;/code>).&lt;/li>
&lt;li>&lt;strong>High &lt;code>top_p&lt;/code> (e.g., &lt;code>0.9&lt;/code> - &lt;code>1.0&lt;/code>):&lt;/strong> Allows for more diverse choices, suitable for creative tasks, similar in effect to higher &lt;code>temperature&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Low &lt;code>top_p&lt;/code> (e.g., &lt;code>0.1&lt;/code> - &lt;code>0.3&lt;/code>):&lt;/strong> Greatly restricts the model's range of choices, making its output very deterministic and conservative, similar in effect to extremely low &lt;code>temperature&lt;/code>.&lt;/li>
&lt;li>&lt;strong>General Recommended Value:&lt;/strong> &lt;code>0.9&lt;/code> is a very common default value as it maintains high quality while allowing for some diversity.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>top_p&lt;/code> vs &lt;code>temperature&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>top_p&lt;/code> is more dynamic and adaptive. When the model is very confident about the next step (sharp probability distribution), &lt;code>top_p&lt;/code> automatically narrows the candidate set, ensuring quality. When the model is less confident (flat distribution), it expands the candidate set, increasing diversity.&lt;/li>
&lt;li>&lt;code>temperature&lt;/code> adjusts the entire distribution &amp;ldquo;equally,&amp;rdquo; regardless of whether the distribution itself is sharp or flat.&lt;/li>
&lt;li>Therefore, &lt;code>top_p&lt;/code> is generally considered a safer and more robust method for controlling diversity than &lt;code>temperature&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="3-topk">3. &lt;code>top_k&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Simply and directly samples only from the &lt;code>k&lt;/code> tokens with the highest probabilities.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong> This is the simplest truncation sampling method. It directly selects the &lt;code>k&lt;/code> tokens with the highest probabilities to form the candidate set, then samples from these &lt;code>k&lt;/code> tokens. All other tokens are ignored.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> Integers, such as &lt;code>1&lt;/code>, &lt;code>10&lt;/code>, &lt;code>50&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>top_k&lt;/code> = 1:&lt;/strong> Equivalent to greedy search, always choosing the most likely word.&lt;/li>
&lt;li>&lt;strong>Recommendation:&lt;/strong> &lt;code>top_k&lt;/code> is typically not the preferred sampling strategy because it's too &amp;ldquo;rigid.&amp;rdquo; In cases where the probability distribution is very flat, it might accidentally exclude many reasonable words; while in cases where the distribution is very sharp, it might include many extremely low-probability, useless words. &lt;code>top_p&lt;/code> is usually a better choice.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="4-repetitionpenalty">4. &lt;code>repetition_penalty&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Applies a penalty to tokens that have already appeared in the context, reducing their probability of being selected again, thereby reducing repetitive content.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong> After calculating &lt;code>logits&lt;/code> but before &lt;code>Softmax&lt;/code>, this parameter iterates through all candidate tokens. If a token has already appeared in the previous context, its &lt;code>logit&lt;/code> value is reduced (typically divided by the value of &lt;code>repetition_penalty&lt;/code>).&lt;/p>
&lt;p>&lt;code>new_logit = logit / penalty&lt;/code> (if token has appeared)
&lt;code>new_logit = logit&lt;/code> (if token has not appeared)&lt;/p>
&lt;p>This way, the final probability of words that have already appeared decreases.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>1.0&lt;/code> to &lt;code>2.0&lt;/code> is common.&lt;/li>
&lt;li>&lt;strong>&lt;code>1.0&lt;/code>:&lt;/strong> No penalty applied (default value).&lt;/li>
&lt;li>&lt;strong>&lt;code>1.1&lt;/code> - &lt;code>1.3&lt;/code>:&lt;/strong> A relatively safe range that can effectively reduce unnecessary repetition without overly affecting normal language expression (such as necessary articles like &amp;ldquo;the&amp;rdquo;).&lt;/li>
&lt;li>&lt;strong>Too High Values:&lt;/strong> May cause the model to deliberately avoid common words, producing unnatural or even strange sentences.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="5-frequencypenalty--presencepenalty">5. &lt;code>frequency_penalty&lt;/code> &amp;amp; &lt;code>presence_penalty&lt;/code>&lt;/h3>
&lt;p>These two parameters are more refined versions of &lt;code>repetition_penalty&lt;/code>.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&lt;code>presence_penalty&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Function:&lt;/strong> Applies a fixed penalty to all tokens that have &lt;strong>appeared at least once&lt;/strong> in the context. It doesn't care how many times the token has appeared; as long as it has appeared, it gets penalized.&lt;/li>
&lt;li>&lt;strong>Underlying Principle:&lt;/strong> &lt;code>new_logit = logit - presence_penalty&lt;/code> (if token has appeared at least once).&lt;/li>
&lt;li>&lt;strong>Scenario:&lt;/strong> This parameter is useful when you want to encourage the model to introduce entirely new concepts and vocabulary, rather than repeatedly discussing topics that have already been mentioned.&lt;/li>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>0.0&lt;/code> to &lt;code>2.0&lt;/code>. Positive values penalize new tokens, negative values encourage them.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>frequency_penalty&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Function:&lt;/strong> The penalty is proportional to the &lt;strong>frequency&lt;/strong> of the token in the context. The more times a word appears, the heavier the penalty it receives.&lt;/li>
&lt;li>&lt;strong>Underlying Principle:&lt;/strong> &lt;code>new_logit = logit - count(token) * frequency_penalty&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Scenario:&lt;/strong> This parameter is effective when you find the model tends to repeatedly use certain specific high-frequency words (even if they are necessary), leading to monotonous language.&lt;/li>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>0.0&lt;/code> to &lt;code>2.0&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Summary:&lt;/strong> &lt;code>presence_penalty&lt;/code> addresses the question of &amp;ldquo;whether it has appeared,&amp;rdquo; while &lt;code>frequency_penalty&lt;/code> addresses &amp;ldquo;how many times it has appeared.&amp;rdquo;&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="6-seed">6. &lt;code>seed&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> By providing a fixed &lt;code>seed&lt;/code>, you can make the model's output reproducible when other parameters (such as &lt;code>temperature&lt;/code>) remain the same.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Function:&lt;/strong> In machine learning, many operations that seem random are actually &amp;ldquo;pseudo-random,&amp;rdquo; determined by an initial &amp;ldquo;seed.&amp;rdquo; Setting the same seed will produce the same sequence of random numbers. In LLMs, this means the sampling process will be completely deterministic.&lt;/li>
&lt;li>&lt;strong>Scenarios:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Debugging and Testing:&lt;/strong> When you need to verify whether a change has affected the output, fixing the &lt;code>seed&lt;/code> can eliminate randomness interference.&lt;/li>
&lt;li>&lt;strong>Reproducible Research:&lt;/strong> Reproducibility is crucial in academic research.&lt;/li>
&lt;li>&lt;strong>Generating Consistent Content:&lt;/strong> When you need the model to consistently produce outputs in the same style for the same input.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Note:&lt;/strong> For complete reproduction, &lt;strong>all&lt;/strong> generation parameters (&lt;code>prompt&lt;/code>, &lt;code>model&lt;/code>, &lt;code>temperature&lt;/code>, &lt;code>top_p&lt;/code>, etc.) must be identical.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="part-2-deployment-serving-parameters--optimizing-service-performance-and-capacity">Part 2: Deployment (Serving) Parameters — Optimizing Service Performance and Capacity&lt;/h3>
&lt;p>Deployment parameters determine how an LLM inference service manages GPU resources, handles concurrent requests, and optimizes overall throughput and latency. These parameters are particularly important in high-performance inference engines like vLLM.&lt;/p>
&lt;h3 id="1-gpumemoryutilization">1. &lt;code>gpu_memory_utilization&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Controls the proportion of GPU memory that vLLM can use, with the core purpose of reserving space for the &lt;strong>KV Cache&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle (PagedAttention):&lt;/strong>
The core of vLLM is the PagedAttention mechanism. Traditional attention mechanisms pre-allocate a continuous, maximum-length memory space for each request to store the Key-Value (KV) Cache. This leads to severe memory waste, as most requests are far shorter than the maximum length.&lt;/p>
&lt;p>PagedAttention manages the KV Cache like virtual memory in an operating system:&lt;/p>
&lt;ol>
&lt;li>It breaks down each sequence's KV Cache into many small, fixed-size &amp;ldquo;blocks.&amp;rdquo;&lt;/li>
&lt;li>These blocks can be stored non-contiguously in GPU memory.&lt;/li>
&lt;li>A central &amp;ldquo;Block Manager&amp;rdquo; is responsible for allocating and releasing these blocks.&lt;/li>
&lt;/ol>
&lt;p>&lt;code>gpu_memory_utilization&lt;/code> tells vLLM: &amp;ldquo;You can use this much proportion of the total GPU memory for free management (mainly storing model weights and physical blocks of KV Cache).&amp;rdquo;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Impact:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> &lt;code>(0.0, 1.0]&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Default Value:&lt;/strong> &lt;code>0.9&lt;/code> (i.e., 90%).&lt;/li>
&lt;li>&lt;strong>Higher Values (e.g., &lt;code>0.95&lt;/code>):&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> vLLM has more memory for KV Cache, supporting longer contexts and larger batch sizes, thereby increasing throughput.&lt;/li>
&lt;li>&lt;strong>Risk:&lt;/strong> If set too high, there might not be enough spare memory for CUDA kernels, drivers, or other system processes, easily leading to &lt;strong>OOM (Out of Memory)&lt;/strong> errors.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Lower Values (e.g., &lt;code>0.8&lt;/code>):&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> Safer, less prone to OOM, reserves more memory for the system and other applications.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Reduced available space for KV Cache, potentially causing vLLM to struggle with high concurrency or long sequence requests, degrading performance. When KV Cache is insufficient, vLLM triggers &lt;strong>Preemption&lt;/strong>, swapping out some running sequences and waiting to swap them back in when there's enough space, severely affecting latency. vLLM's warning log &lt;code>&amp;quot;there is not enough KV cache space. This can affect the end-to-end performance.&amp;quot;&lt;/code> is reminding you of this issue.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Start with the default value of &lt;code>0.9&lt;/code>.&lt;/li>
&lt;li>If you encounter OOM, gradually lower this value.&lt;/li>
&lt;li>If you encounter many preemption warnings and confirm no other processes are occupying large amounts of GPU memory, you can gradually increase this value.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="2-maxnumseqs">2. &lt;code>max_num_seqs&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Limits the maximum number of sequences (requests) that the vLLM scheduler can process &lt;strong>in one iteration (or one batch)&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong>
vLLM's scheduler selects a batch of requests from the waiting queue in each processing cycle. This parameter directly limits the size of this &amp;ldquo;batch.&amp;rdquo; Together with &lt;code>max_num_batched_tokens&lt;/code> (which limits the total number of tokens across all sequences in a batch), it determines the scale of batch processing.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Impact:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> Positive integers, such as &lt;code>16&lt;/code>, &lt;code>64&lt;/code>, &lt;code>256&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Higher Values:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> Allows for higher concurrency, potentially improving GPU utilization and overall throughput.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Requires more intermediate memory (e.g., for storing &lt;code>logits&lt;/code> and sampling states) and may increase the latency of individual batches. If set too high, even if KV Cache still has space, OOM might occur due to insufficient temporary memory.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Lower Values:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> More memory-friendly, potentially lower latency for individual batches.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Limits concurrency capability, potentially leading to underutilization of GPU and decreased throughput.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>This value needs to be adjusted based on your GPU memory size, model size, and expected concurrent load.&lt;/li>
&lt;li>For high-concurrency scenarios, try gradually increasing this value while monitoring GPU utilization and memory usage.&lt;/li>
&lt;li>For interactive, low-latency scenarios, consider setting this value lower.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="3-maxmodellen">3. &lt;code>max_model_len&lt;/code>&lt;/h3>
&lt;p>&lt;strong>In one sentence:&lt;/strong> Sets the &lt;strong>maximum context length&lt;/strong> the model can process (including both prompt and generated tokens).&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Underlying Principle:&lt;/strong>
This parameter directly determines how much logical space vLLM needs to reserve for the KV Cache. For example, if &lt;code>max_model_len&lt;/code> = &lt;code>4096&lt;/code>, vLLM must ensure its memory management mechanism can support storing KV pairs for up to &lt;code>4096&lt;/code> tokens per sequence.
This affects vLLM's memory planning at startup, such as the size of Position Embeddings.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Value Range and Impact:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Range:&lt;/strong> Positive integers, cannot exceed the maximum length the model was originally trained on.&lt;/li>
&lt;li>&lt;strong>Higher Values:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> Can handle longer documents and more complex contexts.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> &lt;strong>Significantly increases&lt;/strong> memory consumption. Each token needs to store KV Cache; doubling the length roughly doubles the memory usage. Even if current requests are short, vLLM needs to prepare for potentially long requests, which occupies more KV Cache blocks.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Lower Values:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> &lt;strong>Significantly saves&lt;/strong> GPU memory. If you know your application scenario will never exceed 1024 tokens, setting this value to 1024 instead of the default 4096 or 8192 will free up a large amount of KV Cache space, supporting higher concurrency.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Any requests exceeding this length will be rejected or truncated.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Recommendations:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Set as needed!&lt;/strong> This is one of the most effective parameters for optimizing vLLM memory usage. Based on your actual application scenario, set this value to a reasonable maximum with some margin.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="4-tensorparallelsize--pipelineparallelsize">4. &lt;code>tensor_parallel_size&lt;/code> &amp;amp; &lt;code>pipeline_parallel_size&lt;/code>&lt;/h3>
&lt;p>These two parameters are used for deploying extremely large models across multiple GPUs or nodes.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&lt;code>tensor_parallel_size&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Function:&lt;/strong> Divides &lt;strong>each layer&lt;/strong> of the model (such as a large weight matrix) into &lt;code>N&lt;/code> parts (&lt;code>N&lt;/code> = &lt;code>tensor_parallel_size&lt;/code>), placing them on &lt;code>N&lt;/code> different GPUs. During computation, each GPU only processes its own portion of the data, then exchanges necessary results through high-speed interconnects (like NVLink) via All-Reduce operations, finally merging to get the complete output.&lt;/li>
&lt;li>&lt;strong>Scenario:&lt;/strong> Used when a single model's volume exceeds the memory of a single GPU. For example, a 70B model cannot fit into a single 40GB A100, but can be deployed across two A100s by setting &lt;code>tensor_parallel_size=2&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Impact:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> Achieves model parallelism, solving the problem of models not fitting on a single card.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Introduces significant cross-GPU communication overhead, potentially affecting latency. Requires high-speed interconnects between GPUs.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>pipeline_parallel_size&lt;/code>:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Function:&lt;/strong> Assigns &lt;strong>different layers&lt;/strong> of the model to different GPUs or nodes. For example, placing layers 1-10 on GPU 1, layers 11-20 on GPU 2, and so on. Data flows through these GPUs like a pipeline.&lt;/li>
&lt;li>&lt;strong>Scenario:&lt;/strong> Used when the model is extremely large and needs to be deployed across multiple nodes (machines).&lt;/li>
&lt;li>&lt;strong>Impact:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Advantage:&lt;/strong> Can scale the model to any number of GPUs/nodes.&lt;/li>
&lt;li>&lt;strong>Disadvantage:&lt;/strong> Creates &amp;ldquo;pipeline bubbles&amp;rdquo; as additional overhead, where some GPUs are idle during the start and end phases of the pipeline, reducing utilization.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Combined Use:&lt;/strong>
vLLM supports using both parallelism strategies simultaneously for efficient deployment of giant models on large clusters.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="summary-and-best-practices">Summary and Best Practices&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">Scenario&lt;/th>
&lt;th align="left">&lt;code>temperature&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>top_p&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>repetition_penalty&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>gpu_memory_utilization&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>max_num_seqs&lt;/code>&lt;/th>
&lt;th align="left">&lt;code>max_model_len&lt;/code>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">&lt;strong>Code Generation/Factual Q&amp;amp;A&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.0&lt;/code> - &lt;code>0.2&lt;/code>&lt;/td>
&lt;td align="left">(Not recommended to modify)&lt;/td>
&lt;td align="left">&lt;code>1.0&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (Default)&lt;/td>
&lt;td align="left">Adjust based on concurrency&lt;/td>
&lt;td align="left">Set as needed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Article Summarization/Translation&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.2&lt;/code> - &lt;code>0.5&lt;/code>&lt;/td>
&lt;td align="left">(Not recommended to modify)&lt;/td>
&lt;td align="left">&lt;code>1.1&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">Adjust based on concurrency&lt;/td>
&lt;td align="left">Set to maximum possible document length&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>General Chat/Copywriting&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.7&lt;/code> (Default)&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (Recommended)&lt;/td>
&lt;td align="left">&lt;code>1.1&lt;/code> - &lt;code>1.2&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">Adjust based on concurrency&lt;/td>
&lt;td align="left">Set as needed, e.g., &lt;code>4096&lt;/code>|&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Creative Writing/Brainstorming&lt;/strong>&lt;/td>
&lt;td align="left">&lt;code>0.8&lt;/code> - &lt;code>1.2&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.95&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>1.0&lt;/code>&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code>&lt;/td>
&lt;td align="left">Adjust based on concurrency&lt;/td>
&lt;td align="left">Set as needed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>High Concurrency Throughput Optimization&lt;/strong>&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">Try &lt;code>0.9&lt;/code> - &lt;code>0.95&lt;/code>&lt;/td>
&lt;td align="left">Gradually increase&lt;/td>
&lt;td align="left">Set to the &lt;strong>minimum&lt;/strong> value that meets business needs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Low Latency Interaction Optimization&lt;/strong>&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">&lt;code>0.9&lt;/code> (Default)&lt;/td>
&lt;td align="left">Set to lower values (e.g., &lt;code>16-64&lt;/code>)&lt;/td>
&lt;td align="left">Set as needed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Extremely Memory Constrained&lt;/strong>&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">(Task dependent)&lt;/td>
&lt;td align="left">Lower to &lt;code>0.8&lt;/code>&lt;/td>
&lt;td align="left">Set to lower values&lt;/td>
&lt;td align="left">Set to the &lt;strong>minimum&lt;/strong> value that meets business needs&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Final Recommendations:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Start with Generation Parameters:&lt;/strong> First adjust &lt;code>temperature&lt;/code> or &lt;code>top_p&lt;/code> to achieve satisfactory output quality.&lt;/li>
&lt;li>&lt;strong>Set Deployment Parameters as Needed:&lt;/strong> When deploying, first set &lt;code>max_model_len&lt;/code> to a reasonable minimum value based on your application scenario.&lt;/li>
&lt;li>&lt;strong>Monitor and Iterate:&lt;/strong> Start with the default &lt;code>gpu_memory_utilization=0.9&lt;/code> and a moderate &lt;code>max_num_seqs&lt;/code>. Observe memory usage and preemption situations through monitoring tools (such as &lt;code>nvidia-smi&lt;/code> and vLLM logs), then gradually adjust these values to find the optimal balance for your specific hardware and workload.&lt;/li>
&lt;/ol></description></item><item><title>vLLM Technical Guide: High-Performance LLM Inference Engine</title><link>https://ziyanglin.netlify.app/en/post/vllm-documentation/</link><pubDate>Thu, 26 Jun 2025 01:05:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/en/post/vllm-documentation/</guid><description>&lt;h2 id="1-introduction-to-vllm">1. Introduction to vLLM&lt;/h2>
&lt;p>vLLM is an open-source inference and serving engine designed for large language models (LLMs), renowned for its high throughput and memory efficiency. In the field of LLM serving, vLLM addresses a core pain point: traditional inference systems are inefficient when handling the key-value cache (KV Cache) in Transformer models&amp;rsquo; attention mechanism, resulting in significant memory waste and limited inference speed.&lt;/p>
&lt;p>The memory bottleneck in LLM inference primarily stems from the KV Cache. This cache stores attention keys and values for each previous token in a sequence to accelerate the generation of subsequent tokens. However, the size of the KV Cache is dynamic and difficult to predict, creating enormous challenges for memory management. Traditional systems (like HuggingFace Transformers) typically pre-allocate a large continuous memory space to store the KV Cache, leading to severe memory fragmentation and waste.&lt;/p>
&lt;p>vLLM fundamentally solves this problem by introducing its core innovation: the &lt;strong>PagedAttention&lt;/strong> mechanism.&lt;/p>
&lt;h2 id="2-core-features-and-advantages">2. Core Features and Advantages&lt;/h2>
&lt;p>vLLM stands out among numerous LLM inference frameworks thanks to several key features:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Extremely High Throughput&lt;/strong>: Through PagedAttention and Continuous Batching, vLLM significantly improves GPU utilization. Its throughput is several times higher than HuggingFace Transformers and outperforms other mainstream inference libraries.&lt;/li>
&lt;li>&lt;strong>Efficient Memory Management&lt;/strong>: The PagedAttention mechanism divides the KV Cache into non-continuous memory blocks, greatly reducing internal and external memory fragmentation. According to official data, it can save up to 55% of memory, meaning you can load larger models or serve more concurrent requests with the same hardware.&lt;/li>
&lt;li>&lt;strong>Flexible Decoding Strategies&lt;/strong>: vLLM supports various complex decoding algorithms, including Parallel Sampling, Beam Search, and Top-K/Top-P sampling, meeting the needs of different application scenarios.&lt;/li>
&lt;li>&lt;strong>OpenAI API Compatibility&lt;/strong>: vLLM provides a service endpoint that is fully compatible with the OpenAI API. This means you can seamlessly integrate vLLM into existing application ecosystems built on the OpenAI API with just a few configuration changes.&lt;/li>
&lt;li>&lt;strong>Distributed Inference&lt;/strong>: For ultra-large models that cannot fit on a single GPU, vLLM supports Tensor Parallelism, distributing model weights and computational load across multiple GPUs for efficient distributed inference.&lt;/li>
&lt;li>&lt;strong>Streaming and Structured Output&lt;/strong>: Supports streaming of generated tokens and can produce structured outputs in specific formats (such as JSON Schema or regular expressions) through Guided Generation.&lt;/li>
&lt;/ul>
&lt;h2 id="3-core-architecture-deep-dive-into-pagedattention">3. Core Architecture: Deep Dive into PagedAttention&lt;/h2>
&lt;p>PagedAttention is the soul of vLLM, with its design inspiration coming from the paging technique used in modern operating systems to manage virtual memory.&lt;/p>
&lt;h3 id="31-working-principle">3.1 Working Principle&lt;/h3>
&lt;p>In traditional methods, the KV Cache for each sequence is stored in continuous memory space. While this approach seems simple, it leads to severe memory fragmentation due to the vast differences in sequence lengths.&lt;/p>
&lt;p>PagedAttention divides each sequence's KV Cache into fixed-size &lt;strong>blocks&lt;/strong>. Each block can store keys and values for a fixed number of tokens. During inference, vLLM's core scheduler dynamically allocates these blocks to sequences as needed.&lt;/p>
&lt;p>The advantages of this design include:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Eliminating Internal Fragmentation&lt;/strong>: Since blocks are of fixed size, a sequence's last block may have some unused space, but this waste is far less than that caused by reserving continuous memory for the entire sequence.&lt;/li>
&lt;li>&lt;strong>Flexible Memory Allocation&lt;/strong>: Blocks are stored in non-continuous memory space, making memory management more flexible, similar to how operating systems manage physical memory pages.&lt;/li>
&lt;li>&lt;strong>Efficient Memory Sharing&lt;/strong>: PagedAttention makes sharing KV Cache between different sequences exceptionally simple and efficient. For example, in parallel sampling or beam search, multiple candidate sequences originate from the same prompt. vLLM allows these sequences to share KV blocks storing the prompt portion, only needing to allocate new, independent blocks for each sequence when generating new tokens. This &amp;ldquo;Copy-on-Write&amp;rdquo; mechanism greatly reduces the memory overhead of complex decoding algorithms.&lt;/li>
&lt;/ol>
&lt;p>Below is a Mermaid diagram that more intuitively illustrates PagedAttention's memory management approach:&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
subgraph Physical_Memory [KV Cache Physical Memory]
direction LR
B1(Block 1)
B2(Block 2)
B3(Block 3)
B4(Block 4)
B5(Block 5)
B6(Block 6)
B7(Block 7)
B8(Block 8)
end
subgraph Logical_View [Sequence Logical View]
direction TB
subgraph Seq1 [Sequence 1]
P1(Prompt) --&amp;gt; T1(Token 1)
end
subgraph Seq2 [Sequence 2]
P2(Prompt) --&amp;gt; T2(Token 1) --&amp;gt; T3(Token 2)
end
subgraph Seq3 [Parallel Sampling]
P3(Prompt) --&amp;gt; T4(Token 1a)
P3 --&amp;gt; T5(Token 1b)
end
end
subgraph Block_Table [Block Table]
direction TB
Map1[&amp;quot;Seq 1: [B1, B5]&amp;quot;]
Map2[&amp;quot;Seq 2: [B2, B6, B8]&amp;quot;]
Map3[&amp;quot;Seq 3a: [B3, B7]&amp;quot;]
Map4[&amp;quot;Seq 3b: [B3, B4]&amp;quot;]
end
Seq1 --&amp;gt; Map1
Seq2 --&amp;gt; Map2
Seq3 --&amp;gt; Map3
Seq3 --&amp;gt; Map4
Map1 --&amp;gt; B1
Map1 --&amp;gt; B5
Map2 --&amp;gt; B2
Map2 --&amp;gt; B6
Map2 --&amp;gt; B8
Map3 --&amp;gt; B3
Map3 --&amp;gt; B7
Map4 --&amp;gt; B3
Map4 --&amp;gt; B4
style B3 fill:#f9f,stroke:#333,stroke-width:2px
linkStyle 8 stroke-width:2px,stroke:green,fill:none;
linkStyle 11 stroke-width:2px,stroke:green,fill:none;
linkStyle 12 stroke-width:2px,stroke:green,fill:none;
&lt;/code>&lt;/pre>
&lt;p>&lt;em>Diagram explanation:&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>KV Cache Physical Memory&lt;/strong>: Represents non-continuous physical memory blocks on the GPU.&lt;/li>
&lt;li>&lt;strong>Sequence Logical View&lt;/strong>: Represents multiple requests (sequences) being processed.&lt;/li>
&lt;li>&lt;strong>Block Table&lt;/strong>: vLLM's core component that maps logical token positions to physical memory blocks.&lt;/li>
&lt;li>&lt;strong>Memory Sharing&lt;/strong>: Note that the two branches in &amp;ldquo;Parallel Sampling&amp;rdquo; (3a and 3b) share the same Prompt block (B3), demonstrating PagedAttention's efficient memory sharing.&lt;/li>
&lt;/ul>
&lt;h3 id="32-continuous-batching">3.2 Continuous Batching&lt;/h3>
&lt;p>Based on PagedAttention, vLLM implements a more advanced batching strategy—continuous batching. Traditional static batching requires waiting for all sequences in a batch to complete generation before processing the next batch. Continuous batching, however, allows new requests to be inserted into the batch immediately after a sequence in the batch completes generation, avoiding GPU idle waiting and further improving throughput.&lt;/p>
&lt;p>Below is a comparison of the two batching methods using a Mermaid sequence diagram:&lt;/p>
&lt;pre>&lt;code class="language-mermaid">sequenceDiagram
participant C as Client
participant S as Server
participant G as GPU
note over C, G: --- Static Batching ---
C-&amp;gt;&amp;gt;S: Request [R1, R2, R3, R4]
S-&amp;gt;&amp;gt;G: Process Batch 1 [R1, R2, R3, R4]
note right of G: All requests process in parallel
G--&amp;gt;&amp;gt;S: Batch 1 Finished
note right of S: Wait for the entire batch to complete
S--&amp;gt;&amp;gt;C: Response [O1, O2, O3, O4]
C-&amp;gt;&amp;gt;S: Request [R5, R6]
S-&amp;gt;&amp;gt;G: Process Batch 2 [R5, R6]
note over C, G: --- Continuous Batching ---
C-&amp;gt;&amp;gt;S: Request [R1, R2, R3, R4]
S-&amp;gt;&amp;gt;G: Process [R1, R2, R3, R4]
G--&amp;gt;&amp;gt;S: R2 Finished
S--&amp;gt;&amp;gt;C: Response O2
C-&amp;gt;&amp;gt;S: New Request R5
S-&amp;gt;&amp;gt;G: Add R5 to queue (GPU is not idle)
note right of G: R1, R3, R4, R5 are now processing
G--&amp;gt;&amp;gt;S: R4 Finished
S--&amp;gt;&amp;gt;C: Response O4
&lt;/code>&lt;/pre>
&lt;h2 id="4-quick-start-guide">4. Quick Start Guide&lt;/h2>
&lt;p>Below, we'll demonstrate how to install and use vLLM through a few simple steps.&lt;/p>
&lt;h3 id="41-installation">4.1 Installation&lt;/h3>
&lt;p>You can install vLLM using either &lt;code>pip&lt;/code> or &lt;code>uv&lt;/code> (a faster package installation tool). Using &lt;code>uv&lt;/code> is recommended as it can automatically detect your CUDA version and install the matching PyTorch backend.&lt;/p>
&lt;p>&lt;strong>Using uv (recommended):&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash"># Create and activate a virtual environment
uv venv
source .venv/bin/activate
# Install vLLM
uv pip install vllm --torch-backend=auto
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Using pip:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install vllm
&lt;/code>&lt;/pre>
&lt;h3 id="42-offline-inference">4.2 Offline Inference&lt;/h3>
&lt;p>The &lt;code>vllm.LLM&lt;/code> class makes offline inference very convenient.&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM, SamplingParams
# Define input prompts
prompts = [
&amp;quot;Hello, my name is&amp;quot;,
&amp;quot;The capital of France is&amp;quot;,
&amp;quot;The future of AI is&amp;quot;,
]
# Define sampling parameters
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
# Initialize the LLM engine (model will be automatically downloaded from Hugging Face)
llm = LLM(model=&amp;quot;facebook/opt-125m&amp;quot;)
# Generate text
outputs = llm.generate(prompts, sampling_params)
# Print results
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f&amp;quot;Prompt: {prompt!r}, Generated text: {generated_text!r}&amp;quot;)
&lt;/code>&lt;/pre>
&lt;h3 id="43-launching-an-openaicompatible-server">4.3 Launching an OpenAI-Compatible Server&lt;/h3>
&lt;p>One of vLLM's most powerful features is its built-in API server. With just one command, you can start a service compatible with the OpenAI API.&lt;/p>
&lt;pre>&lt;code class="language-bash">vllm serve Qwen/Qwen2.5-1.5B-Instruct
&lt;/code>&lt;/pre>
&lt;p>By default, the server will run on &lt;code>http://localhost:8000&lt;/code>.&lt;/p>
&lt;h3 id="44-interacting-with-the-server">4.4 Interacting with the Server&lt;/h3>
&lt;p>You can interact with the server using &lt;code>curl&lt;/code> or the &lt;code>openai&lt;/code> Python client.&lt;/p>
&lt;p>&lt;strong>Using curl:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;Qwen/Qwen2.5-1.5B-Instruct&amp;quot;,
&amp;quot;prompt&amp;quot;: &amp;quot;San Francisco is a&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 7,
&amp;quot;temperature&amp;quot;: 0
}'
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Using the OpenAI Python client:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from openai import OpenAI
client = OpenAI(
base_url=&amp;quot;http://localhost:8000/v1&amp;quot;,
api_key=&amp;quot;not-used&amp;quot; # API key is not required
)
completion = client.chat.completions.create(
model=&amp;quot;Qwen/Qwen2.5-1.5B-Instruct&amp;quot;,
messages=[
{&amp;quot;role&amp;quot;: &amp;quot;system&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;You are a helpful assistant.&amp;quot;},
{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Who won the world series in 2020?&amp;quot;}
]
)
print(completion.choices[0].message)
&lt;/code>&lt;/pre>
&lt;h2 id="5-model-serving">5. Model Serving&lt;/h2>
&lt;h3 id="51-distributed-serving">5.1 Distributed Serving&lt;/h3>
&lt;p>If a model is too large to fit on a single GPU, you can distribute it across multiple GPUs using tensor parallelism.&lt;/p>
&lt;pre>&lt;code class="language-bash"># Start a service on 4 GPUs
vllm serve facebook/opt-13b --tensor-parallel-size 4
&lt;/code>&lt;/pre>
&lt;h3 id="52-docker-deployment">5.2 Docker Deployment&lt;/h3>
&lt;p>vLLM provides official Docker images for convenient containerized deployment.&lt;/p>
&lt;pre>&lt;code class="language-bash">docker run --runtime nvidia --gpus all \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env &amp;quot;HUGGING_FACE_HUB_TOKEN=&amp;lt;your-hf-token&amp;gt;&amp;quot; \
-p 8000:8000 \
--ipc=host \
vllm/vllm-openai:latest \
--model mistralai/Mistral-7B-v0.1
&lt;/code>&lt;/pre>
&lt;h2 id="6-advanced-features">6. Advanced Features&lt;/h2>
&lt;h3 id="61-structured-outputs">6.1 Structured Outputs&lt;/h3>
&lt;p>vLLM supports various ways to constrain the model's output format, which is crucial for applications requiring reliable, parsable outputs.&lt;/p>
&lt;p>&lt;strong>Generating JSON using Pydantic models:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from pydantic import BaseModel
from openai import OpenAI
client = OpenAI(base_url=&amp;quot;http://localhost:8000/v1&amp;quot;, api_key=&amp;quot;dummy&amp;quot;)
model = client.models.list().data[0].id
class People(BaseModel):
name: str
age: int
completion = client.chat.completions.create(
model=model,
messages=[
{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Generate a JSON with the name and age of one random person.&amp;quot;}
],
response_format={
&amp;quot;type&amp;quot;: &amp;quot;json_schema&amp;quot;,
&amp;quot;json_schema&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;people&amp;quot;,
&amp;quot;schema&amp;quot;: People.model_json_schema()
}
},
)
print(completion.choices[0].message.content)
&lt;/code>&lt;/pre>
&lt;h3 id="62-lora-support">6.2 LoRA Support&lt;/h3>
&lt;p>vLLM can efficiently serve multiple LoRA adapters on the same base model. This is particularly useful for scenarios requiring customized models for different customers or tasks.&lt;/p>
&lt;p>&lt;strong>Starting a server with LoRA support:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM
llm = LLM(model=&amp;quot;meta-llama/Llama-2-7b-hf&amp;quot;, enable_lora=True)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Specifying a LoRA adapter in a request:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;sql-lora&amp;quot;, # Specify the LoRA model ID
&amp;quot;prompt&amp;quot;: &amp;quot;San Francisco is a&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 7
}'
&lt;/code>&lt;/pre>
&lt;h3 id="63-quantization">6.3 Quantization&lt;/h3>
&lt;p>Quantization is a technique to reduce model size and memory usage by lowering the precision of model weights. vLLM supports various quantization schemes, such as AWQ and FP8 KV cache.&lt;/p>
&lt;p>&lt;strong>Enabling FP8 KV cache:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM
llm = LLM(
model=&amp;quot;meta-llama/Llama-2-7b-chat-hf&amp;quot;,
kv_cache_dtype=&amp;quot;fp8&amp;quot;,
calculate_kv_scales=True # Dynamically calculate quantization scales
)
&lt;/code>&lt;/pre>
&lt;h2 id="7-framework-integration">7. Framework Integration&lt;/h2>
&lt;p>vLLM can be easily integrated with popular LLM application frameworks like Langchain and LlamaIndex for building complex systems such as Retrieval-Augmented Generation (RAG). Typically, vLLM serves as a backend providing fast LLM inference and embedding generation services.&lt;/p>
&lt;p>&lt;strong>Installing related dependencies:&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install -U vllm langchain_openai langchain_community
&lt;/code>&lt;/pre>
&lt;p>Afterward, in Langchain, you can point the &lt;code>base_url&lt;/code> of &lt;code>ChatOpenAI&lt;/code> or &lt;code>OpenAIEmbeddings&lt;/code> to your vLLM server's address to complete the integration.&lt;/p>
&lt;h2 id="8-conclusion">8. Conclusion&lt;/h2>
&lt;p>Through its innovative PagedAttention architecture, vLLM successfully addresses memory management and performance bottlenecks in LLM inference, providing developers with an extremely efficient, flexible, and easy-to-use inference serving engine. Whether conducting quick offline experiments or deploying production-grade, high-concurrency LLM services, vLLM demonstrates excellent performance and powerful functionality. As the community continues to develop, vLLM is becoming one of the standard tools in the field of LLM serving.&lt;/p></description></item><item><title>LoRA Technical Guide: Parameter-Efficient Fine-Tuning for Large Models</title><link>https://ziyanglin.netlify.app/en/post/lora-documentation/</link><pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/en/post/lora-documentation/</guid><description>&lt;h2 id="1-introduction-why-lora">1. Introduction: Why LoRA?&lt;/h2>
&lt;p>In today's rapidly evolving landscape of Large Language Models (LLMs) and generative AI, we've witnessed an explosive growth in model sizes, ranging from hundreds of millions to trillions of parameters. These massive models demonstrate remarkable capabilities across various tasks. However, a significant challenge emerges: how can we fine-tune these models for specific downstream tasks?&lt;/p>
&lt;p>The traditional &lt;strong>Full Fine-Tuning&lt;/strong> approach, which updates all parameters of a model, faces severe challenges:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>High computational cost&lt;/strong>: Fine-tuning a model with billions of parameters requires enormous computational resources and hundreds of GB of GPU memory, which is prohibitively expensive for most developers and small to medium-sized enterprises.&lt;/li>
&lt;li>&lt;strong>Massive storage requirements&lt;/strong>: Each fine-tuned model for a specific task requires storing a complete model copy, leading to rapidly escalating storage costs.&lt;/li>
&lt;li>&lt;strong>Deployment difficulties&lt;/strong>: Maintaining and switching between multiple massive model copies for different tasks in a production environment is a nightmare.&lt;/li>
&lt;/ul>
&lt;p>To address these pain points, &lt;strong>Parameter-Efficient Fine-Tuning (PEFT)&lt;/strong> techniques have emerged. The core idea is to freeze most parameters of the pre-trained model during fine-tuning and only adjust a small portion (typically far less than 1% of the total) of new or specific parameters.&lt;/p>
&lt;p>Among the various PEFT techniques, &lt;strong>LoRA (Low-Rank Adaptation of Large Language Models)&lt;/strong> stands out for its excellent performance, efficiency, and implementation simplicity, becoming one of the most mainstream and widely applied solutions today. This document will provide an in-depth yet accessible introduction to the core principles of LoRA and offer detailed practical guidance.&lt;/p>
&lt;h2 id="2-core-principles-the-magic-of-lora">2. Core Principles: The Magic of LoRA&lt;/h2>
&lt;p>LoRA's core assumption is that &lt;strong>the weight changes in large language models when adapting to new tasks are low-rank&lt;/strong>. In other words, although the weight matrix &lt;code>W&lt;/code> of the pre-trained model is very large (e.g., &lt;code>d x d&lt;/code> dimensions), the weight change &lt;code>ΔW&lt;/code> during fine-tuning has a very low &amp;ldquo;intrinsic rank.&amp;rdquo;&lt;/p>
&lt;p>Based on this assumption, LoRA doesn't directly update &lt;code>W&lt;/code>, but instead approximates &lt;code>ΔW&lt;/code> by training two smaller, low-rank matrices &lt;code>B&lt;/code> and &lt;code>A&lt;/code>, such that &lt;code>ΔW ≈ BA&lt;/code>.&lt;/p>
&lt;ul>
&lt;li>&lt;code>W&lt;/code> is the pre-trained, frozen weight matrix.&lt;/li>
&lt;li>&lt;code>A&lt;/code> is an &lt;code>r x d&lt;/code> dimensional matrix, where &lt;code>r&lt;/code> is a rank much smaller than &lt;code>d&lt;/code>.&lt;/li>
&lt;li>&lt;code>B&lt;/code> is a &lt;code>d x r&lt;/code> dimensional matrix.&lt;/li>
&lt;/ul>
&lt;p>During fine-tuning, only the parameters of matrices &lt;code>A&lt;/code> and &lt;code>B&lt;/code> are trainable. The forward propagation computation process is accordingly changed to:&lt;/p>
&lt;p>&lt;code>h = Wx + BAx&lt;/code>&lt;/p>
&lt;p>Here's a diagram that illustrates this process more intuitively:&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[Input x] --&amp;gt; B(Pre-trained weights W);
A --&amp;gt; C(Low-rank matrix A);
C --&amp;gt; D(Low-rank matrix B);
B --&amp;gt; E[Wx];
D --&amp;gt; F[BAx];
E --&amp;gt; G((Sum));
F --&amp;gt; G;
G --&amp;gt; H[Final output h];
style B fill:#eee,stroke:#333,stroke-width:2px,stroke-dasharray: 5, 5
style C fill:#9cf,stroke:#333,stroke-width:2px
style D fill:#9cf,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;p>Where &lt;code>x&lt;/code> is the input and &lt;code>h&lt;/code> is the output. This approach greatly reduces the number of parameters that need to be trained. For example, if &lt;code>d = 4096&lt;/code> and &lt;code>r = 8&lt;/code>, the original matrix &lt;code>W&lt;/code> has &lt;code>4096 * 4096 ≈ 16.7M&lt;/code> parameters, while &lt;code>A&lt;/code> and &lt;code>B&lt;/code> together have only &lt;code>4096 * 8 + 8 * 4096 ≈ 65K&lt;/code> parameters, reducing the parameter count by approximately 256 times!&lt;/p>
&lt;p>&lt;strong>Key parameter &lt;code>r&lt;/code>&lt;/strong>: The rank &lt;code>r&lt;/code> is the most important hyperparameter in LoRA. It controls the size of the low-rank matrices and directly determines the number of new parameters.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Smaller &lt;code>r&lt;/code>&lt;/strong>: Fewer trainable parameters, faster training speed, lower memory usage, but may not fully capture complex features of the task.&lt;/li>
&lt;li>&lt;strong>Larger &lt;code>r&lt;/code>&lt;/strong>: More trainable parameters, stronger model fitting capability, but increases computational cost and risk of overfitting.
In practice, &lt;code>r&lt;/code> is typically set to 8, 16, 32, or 64, which achieves a good balance between performance and efficiency.&lt;/li>
&lt;/ul>
&lt;h2 id="3-significant-advantages-of-lora">3. Significant Advantages of LoRA&lt;/h2>
&lt;p>Compared to full fine-tuning, LoRA demonstrates overwhelming advantages in multiple aspects:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Extreme parameter efficiency&lt;/strong>: As mentioned above, LoRA only requires training a tiny fraction of parameters. We can see this intuitively through the &lt;code>print_trainable_parameters()&lt;/code> function, where the proportion of trained parameters is typically less than 1%.&lt;/li>
&lt;li>&lt;strong>Faster training speed&lt;/strong>: With a significantly reduced number of parameters for gradient computation and updates, training time is also shortened, accelerating the iteration cycle.&lt;/li>
&lt;li>&lt;strong>Lower hardware requirements&lt;/strong>: LoRA significantly reduces GPU memory (VRAM) usage during training, making it possible to fine-tune models with tens of billions of parameters on consumer-grade GPUs (such as RTX 3090/4090).&lt;/li>
&lt;li>&lt;strong>Flexibility in deployment and management&lt;/strong>: This is one of LoRA's most attractive advantages. The pre-trained model remains unchanged and can be shared across all tasks. For each downstream task, we only need to save a lightweight (typically just a few MB to tens of MB) LoRA adapter (i.e., the weights of matrices A and B). During deployment, the appropriate adapter can be loaded dynamically according to needs, greatly simplifying model management and switching in multi-task scenarios.&lt;/li>
&lt;/ol>
&lt;h2 id="4-handson-practice-lora-training-methods">4. Hands-on Practice: LoRA Training Methods&lt;/h2>
&lt;p>Below, we'll demonstrate a complete example of how to fine-tune a large model using LoRA with the &lt;code>transformers&lt;/code>, &lt;code>peft&lt;/code>, and &lt;code>trl&lt;/code> libraries from the Hugging Face ecosystem.&lt;/p>
&lt;h3 id="step-1-environment-preparation">Step 1: Environment Preparation&lt;/h3>
&lt;p>First, ensure you have installed the necessary Python libraries:&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install transformers peft trl datasets torch
&lt;/code>&lt;/pre>
&lt;h3 id="step-2-load-model-tokenizer-and-dataset">Step 2: Load Model, Tokenizer, and Dataset&lt;/h3>
&lt;p>We select a pre-trained model as the foundation and load the corresponding tokenizer. At the same time, we load a dataset from the Hugging Face Hub for fine-tuning.&lt;/p>
&lt;pre>&lt;code class="language-python">from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from datasets import load_dataset
# Model ID, can be any supported Causal LM
model_id = &amp;quot;facebook/opt-350m&amp;quot;
# Load pre-trained model
model = AutoModelForCausalLM.from_pretrained(model_id)
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id)
# Load dataset (using English quotes dataset as an example)
dataset = load_dataset(&amp;quot;Abirate/english_quotes&amp;quot;, split=&amp;quot;train&amp;quot;)
&lt;/code>&lt;/pre>
&lt;h3 id="step-3-configure-lora-loraconfig">Step 3: Configure LoRA (&lt;code>LoraConfig&lt;/code>)&lt;/h3>
&lt;p>This is the core step of LoRA fine-tuning. We need to create a &lt;code>LoraConfig&lt;/code> object to define the behavior of the LoRA adapter.&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import LoraConfig
lora_config = LoraConfig(
r=16, # Rank of the low-rank matrices, recommended values are 8, 16, 32
lora_alpha=32, # Scaling factor, typically set to twice the value of r
target_modules=[&amp;quot;q_proj&amp;quot;, &amp;quot;v_proj&amp;quot;], # Specify which model layers to apply LoRA to. For Transformer models, typically q_proj and v_proj
lora_dropout=0.05, # Dropout probability for LoRA layers
bias=&amp;quot;none&amp;quot;, # Whether to train bias terms, &amp;quot;none&amp;quot; means not training
task_type=&amp;quot;CAUSAL_LM&amp;quot; # Task type, here it's causal language modeling
)
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;code>target_modules&lt;/code>: This parameter is crucial. It tells the PEFT library which modules (typically &lt;code>nn.Linear&lt;/code> layers) in the model should have LoRA applied. For most Transformer models, applying it to the query and value projection layers in the Attention mechanism (i.e., &lt;code>q_proj&lt;/code> and &lt;code>v_proj&lt;/code>) is a common practice. You can print the &lt;code>model&lt;/code> object to see the names of all its modules to determine which can be targeted.&lt;/li>
&lt;/ul>
&lt;h3 id="step-4-apply-lora-and-train-with-sfttrainer">Step 4: Apply LoRA and Train with &lt;code>SFTTrainer&lt;/code>&lt;/h3>
&lt;p>The &lt;code>SFTTrainer&lt;/code> (Supervised Fine-tuning Trainer) provided by the &lt;code>trl&lt;/code> library greatly simplifies the fine-tuning process. It has built-in support for &lt;code>peft&lt;/code>, so we just need to pass the model, tokenizer, dataset, and &lt;code>peft_config&lt;/code> to it.&lt;/p>
&lt;pre>&lt;code class="language-python">from trl import SFTTrainer
# Define training parameters
training_args = TrainingArguments(
output_dir=&amp;quot;./lora_finetuned_model&amp;quot;, # Model output directory
num_train_epochs=3, # Number of training epochs
per_device_train_batch_size=4, # Training batch size per device
logging_dir='./logs', # Logging directory
logging_steps=50, # Log every this many steps
learning_rate=2e-4, # Learning rate
)
# Initialize SFTTrainer
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=training_args,
train_dataset=dataset,
peft_config=lora_config, # Pass in LoRA configuration
dataset_text_field=&amp;quot;quote&amp;quot;, # Field name containing text in the dataset
)
# Start training
trainer.train()
# Save the trained LoRA adapter
trainer.save_model()
&lt;/code>&lt;/pre>
&lt;p>After training is complete, an &lt;code>adapter_model.bin&lt;/code> file and an &lt;code>adapter_config.json&lt;/code> file will be generated in the &lt;code>output_dir&lt;/code> directory. These are the lightweight LoRA adapter we've trained.&lt;/p>
&lt;h3 id="step-5-inference-with-the-trained-lora-adapter">Step 5: Inference with the Trained LoRA Adapter&lt;/h3>
&lt;p>For inference, we first load the original pre-trained model, then load the trained LoRA adapter weights.&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import PeftModel
# Load the original, non-fine-tuned model
base_model = AutoModelForCausalLM.from_pretrained(model_id)
# Load the LoRA adapter
model_with_lora = PeftModel.from_pretrained(base_model, &amp;quot;./lora_finetuned_model&amp;quot;)
# Now model_with_lora is a model with LoRA weights integrated, ready for inference
prompt = &amp;quot;The best way to predict the future is to&amp;quot;
inputs = tokenizer(prompt, return_tensors=&amp;quot;pt&amp;quot;)
# Generate text
outputs = model_with_lora.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
&lt;/code>&lt;/pre>
&lt;h2 id="5-lora-model-deployment-from-static-to-dynamic">5. LoRA Model Deployment: From Static to Dynamic&lt;/h2>
&lt;p>After training, efficiently deploying LoRA models into production environments is the crucial next step. LoRA deployment strategies mainly fall into two categories: &lt;strong>Weight Merging (Static Deployment)&lt;/strong> and &lt;strong>Dynamic Adapter Loading (Dynamic Deployment)&lt;/strong>. The following flowcharts illustrate these two paths:&lt;/p>
&lt;p>&lt;strong>Option 1: Weight Merging (Static Deployment)&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[LoRA Training Complete] --&amp;gt; B[Base Model + LoRA Adapter];
B --&amp;gt; C[&amp;quot;Call merge_and_unload()&amp;quot;];
C --&amp;gt; D[Generate standalone full model];
D --&amp;gt; E[Standard deployment];
style D fill:#c9f,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Option 2: Dynamic Adapter Loading (Dynamic Deployment)&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-mermaid">graph TD
A[LoRA Training Complete] --&amp;gt; B[vLLM / TGI server];
B --&amp;gt; C[Load Base Model];
C --&amp;gt; D[Load multiple LoRA Adapters];
D --&amp;gt; E[On-demand inference combinations];
style E fill:#9cf,stroke:#333,stroke-width:2px
&lt;/code>&lt;/pre>
&lt;h3 id="option-1-weight-merging-and-standard-deployment-static">Option 1: Weight Merging and Standard Deployment (Static)&lt;/h3>
&lt;p>This is the simplest and most direct deployment approach. The core idea is to merge the lightweight LoRA adapter weights into the original base model weights, generating a new, standalone full model.&lt;/p>
&lt;p>&lt;strong>Method&lt;/strong>:
Using the &lt;code>merge_and_unload()&lt;/code> method from the &lt;code>peft&lt;/code> library, this process can be easily completed.&lt;/p>
&lt;pre>&lt;code class="language-python">from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
# Assuming model_id and lora_path are defined
base_model = AutoModelForCausalLM.from_pretrained(model_id)
model_with_lora = PeftModel.from_pretrained(base_model, &amp;quot;./lora_finetuned_model&amp;quot;)
# Merge weights
merged_model = model_with_lora.merge_and_unload()
# Now merged_model is a standard Transformers model
# You can save it like any other model
merged_model.save_pretrained(&amp;quot;./merged_lora_model&amp;quot;)
tokenizer.save_pretrained(&amp;quot;./merged_lora_model&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>Afterward, you can load and use this &lt;code>merged_lora_model&lt;/code> just like any regular Hugging Face model.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Advantages&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>Zero inference latency&lt;/strong>: After merging, the inference process is identical to a standard model, with no additional computational overhead.&lt;/li>
&lt;li>&lt;strong>Simple deployment&lt;/strong>: No need for any additional inference framework support, can be used directly with standard libraries like &lt;code>transformers&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Disadvantages&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>Loss of flexibility&lt;/strong>: For each LoRA adapter, you need to save and load a complete model copy, defeating the lightweight purpose of LoRA.&lt;/li>
&lt;li>&lt;strong>High storage cost&lt;/strong>: If you have multiple adapters, the storage overhead is enormous.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="option-2-highperformance-dynamic-deployment-with-vllm-recommended">Option 2: High-Performance Dynamic Deployment with vLLM (Recommended)&lt;/h3>
&lt;p>For scenarios requiring simultaneous service of multiple LoRA adapters, &lt;strong>vLLM&lt;/strong> is currently the industry-leading high-performance inference and serving engine. Through core technologies such as &lt;strong>PagedAttention&lt;/strong>, it achieves efficient management and dynamic loading of multiple LoRA adapters, delivering extremely high throughput without significantly sacrificing performance.&lt;/p>
&lt;p>&lt;strong>Method&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Install vLLM&lt;/strong>:&lt;/p>
&lt;pre>&lt;code class="language-bash">pip install vllm
&lt;/code>&lt;/pre>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Start vLLM server&lt;/strong>:
Use the &lt;code>vllm serve&lt;/code> command to start an OpenAI-compatible API server. The key is to enable LoRA support with &lt;code>--enable-lora&lt;/code> and optionally preload adapters with &lt;code>--lora-modules&lt;/code>.&lt;/p>
&lt;pre>&lt;code class="language-bash"># lora_path points to your trained adapter directory
vllm serve meta-llama/Llama-2-7b-hf \
--enable-lora \
--lora-modules my_sql_lora=/path/to/your/sql_lora_adapter
&lt;/code>&lt;/pre>
&lt;p>Here, we've preloaded an adapter named &lt;code>my_sql_lora&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Send inference requests&lt;/strong>:
You can send requests to the vLLM server using &lt;code>curl&lt;/code> or any HTTP client. Just specify the &lt;code>model&lt;/code> in the request body as the name of your loaded LoRA adapter.&lt;/p>
&lt;pre>&lt;code class="language-bash">curl http://localhost:8000/v1/completions \
-H &amp;quot;Content-Type: application/json&amp;quot; \
-d '{
&amp;quot;model&amp;quot;: &amp;quot;my_sql_lora&amp;quot;,
&amp;quot;prompt&amp;quot;: &amp;quot;Write a SQL query for all users.&amp;quot;,
&amp;quot;max_tokens&amp;quot;: 64
}'
&lt;/code>&lt;/pre>
&lt;p>vLLM will automatically route the request to the corresponding LoRA adapter for inference.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Using Python Client&lt;/strong>:
vLLM also provides a Python API for direct calls in code.&lt;/p>
&lt;pre>&lt;code class="language-python">from vllm import LLM, SamplingParams
from vllm.lora.request import LoRARequest
# Initialize LLM engine with LoRA support
llm = LLM(model=&amp;quot;meta-llama/Llama-2-7b-hf&amp;quot;, enable_lora=True)
sampling_params = SamplingParams(max_tokens=64)
# In the generate call, specify which adapter to use via lora_request
outputs = llm.generate(
&amp;quot;Write a SQL query for all users.&amp;quot;,
sampling_params,
lora_request=LoRARequest(&amp;quot;my_sql_lora&amp;quot;, 1, &amp;quot;/path/to/your/sql_lora_adapter&amp;quot;)
)
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>Advantages&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>Extremely high throughput&lt;/strong>: Designed for large-scale concurrent inference.&lt;/li>
&lt;li>&lt;strong>Dynamic flexibility&lt;/strong>: Can simultaneously serve hundreds or thousands of LoRA adapters, loading them on demand, perfect for multi-tenant scenarios.&lt;/li>
&lt;li>&lt;strong>Memory efficient&lt;/strong>: PagedAttention mechanism effectively manages GPU memory, avoiding waste.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Disadvantages&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>Slightly more complex deployment&lt;/strong>: Requires additional learning and configuration of vLLM service.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="option-3-other-dynamic-deployment-options-eg-tgi">Option 3: Other Dynamic Deployment Options (e.g., TGI)&lt;/h3>
&lt;p>Hugging Face's own &lt;strong>Text Generation Inference (TGI)&lt;/strong> is another powerful production-grade inference server. Similar to vLLM, TGI also supports loading multiple LoRA adapters at startup and dynamically applying them based on incoming request headers. It integrates best with the Hugging Face ecosystem and is a strong competitor to vLLM.&lt;/p>
&lt;h3 id="deployment-options-comparison-summary">Deployment Options Comparison Summary&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th align="left">Feature&lt;/th>
&lt;th align="left">Weight Merging (Static)&lt;/th>
&lt;th align="left">vLLM (Dynamic)&lt;/th>
&lt;th align="left">TGI (Dynamic)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td align="left">&lt;strong>Performance/Throughput&lt;/strong>&lt;/td>
&lt;td align="left">Highest (lowest single request latency)&lt;/td>
&lt;td align="left">Very High&lt;/td>
&lt;td align="left">High&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Flexibility&lt;/strong>&lt;/td>
&lt;td align="left">Low (no dynamic capability)&lt;/td>
&lt;td align="left">Very High&lt;/td>
&lt;td align="left">High&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Deployment Complexity&lt;/strong>&lt;/td>
&lt;td align="left">Low&lt;/td>
&lt;td align="left">Medium&lt;/td>
&lt;td align="left">Medium&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Memory Usage&lt;/strong>&lt;/td>
&lt;td align="left">Very High (N adapters = N times memory)&lt;/td>
&lt;td align="left">Low (efficient sharing)&lt;/td>
&lt;td align="left">Low (efficient sharing)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td align="left">&lt;strong>Suitable Scenarios&lt;/strong>&lt;/td>
&lt;td align="left">Single, fixed tasks&lt;/td>
&lt;td align="left">Multi-tenant, high-concurrency, multi-task scenarios&lt;/td>
&lt;td align="left">Production deployment in Hugging Face ecosystem&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="6-advanced-topics">6. Advanced Topics&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Multi-adapter Management&lt;/strong>: PEFT supports dynamically adding, switching, and disabling multiple adapters on a single model using methods like &lt;code>model.add_adapter()&lt;/code> and &lt;code>model.set_adapter()&lt;/code>, providing great convenience for building flexible multi-task systems.&lt;/li>
&lt;/ul>
&lt;h2 id="7-conclusion">7. Conclusion&lt;/h2>
&lt;p>As a revolutionary parameter-efficient fine-tuning technique, LoRA successfully addresses the high cost challenges of fine-tuning in the era of large models. Through clever low-rank decomposition ideas, it greatly reduces computational resource and storage requirements while maintaining fine-tuning effectiveness. Combined with advanced inference engines like vLLM, LoRA deployment and service have become unprecedentedly efficient and flexible, driving the application of large models in more specific scenarios.&lt;/p></description></item></channel></rss>