dldl.course
Chapter 13 · expert · 55 min

Deployment — serving models in production

Quantization (GPTQ, AWQ, GGUF). Inference engines (vLLM, TGI, Llama.cpp, TensorRT-LLM, Ollama). KV-cache, paged attention, speculative decoding. Latency vs. throughput vs. cost. A real serving recipe.

The three axes: latency, throughput, cost

Production serving is a trade-off between:

  • Latency: time-to-first-token (TTFT) and inter-token latency (ITL). User-facing chat needs TTFT < 500ms.
  • Throughput: tokens/second across all concurrent users. Drives cost per token.
  • Cost: $/1M tokens. Often dictated by GPU hourly cost + utilization.

These pull in different directions. Bigger batch = higher throughput but worse per-request latency. Smaller model = lower TTFT but worse quality. Quantization = cheaper but small quality hit. Pick your priorities before you pick your stack.

Inference-time quantization

Training-time precision (bf16/fp16) is overkill for inference. Quantize the weights:

  • INT8 (bitsandbytes, accelerate): drop-in, ~50% speedup, negligible quality loss.
  • GPTQ (4-bit): post-training quantization with per-channel calibration. Strong quality, widely supported by inference engines.
  • AWQ (4-bit): activation-aware quantization. Often slightly better than GPTQ for chat models.
  • GGUF (Llama.cpp's format): supports 2-8 bit quants (Q2_K, Q3_K_M, Q4_K_M, Q5_K_M, Q8_0). Q4_K_M is the standard 'good enough' default.
  • FP8 (H100/B200): emerging standard with hardware support. Best speed/quality ratio on supported hardware.

Rule of thumb: a Q4_K_M Llama-3 8B (~5GB on disk, ~6GB VRAM) runs on a single 8GB consumer GPU at 30-100 tokens/sec. That's the magic that makes local AI feasible.

KV-cache and paged attention

An autoregressive transformer's per-token cost grows with sequence length because each new token attends to all previous ones. The KV-cache stores K and V activations from previous tokens so they don't need to be recomputed — turns attention's O(T²) cost into O(T) per token.

But KV-cache grows fast: for Llama-3 8B at 4096 tokens, the KV-cache is ~2GB *per concurrent sequence*. Naively this kills batching.

PagedAttention (vLLM): treat the KV-cache like a virtual-memory system. Allocate small fixed-size blocks; map them to the conceptual sequence positions via a page table. Result: 24× higher throughput than naive serving because you can batch many sequences without wasting memory on the longest one.

This is why vLLM is the default open-source serving engine. Two-line API:

from vllm import LLM, SamplingParams
llm = LLM(model='meta-llama/Llama-3-8B-Instruct', dtype='bfloat16', gpu_memory_utilization=0.9)
outputs = llm.generate(prompts, SamplingParams(temperature=0.7, max_tokens=512))

Launch as a server: python -m vllm.entrypoints.openai.api_server --model ... gives you an OpenAI-compatible HTTP endpoint.

Speculative decoding and other latency tricks

Speculative decoding: run a tiny 'draft' model fast, propose N tokens, then have the big model verify them in a single forward pass. If most drafts are accepted, you get the big model's quality at ~2-3× its throughput.

Variants:

  • Vanilla speculative: draft model (e.g. Llama-3 1B) + target (Llama-3 70B).
  • Medusa heads: train extra heads on the target model that predict multiple tokens at once. No draft model needed.
  • EAGLE: hidden-state-level drafting; higher acceptance rate.

Chunked prefill: split a long prompt into chunks; interleave prefill with decoding so the GPU stays busy.

Continuous batching: vLLM, TGI — accept new requests mid-batch, evict finished ones. Dramatically higher utilization than static batching.

The serving-engine landscape

  • vLLM: open-source default. PagedAttention, continuous batching, supports most architectures. OpenAI-compatible server. Best throughput-per-dollar for most workloads.
  • TGI (Text Generation Inference) by HuggingFace: similar feature set, integrates with HF Hub. Good docs.
  • TensorRT-LLM by NVIDIA: best raw performance on NVIDIA hardware, harder to use. Pre-compile graphs per model.
  • Llama.cpp: CPU + GPU, GGUF quantization, smallest deployment footprint. Powers Ollama, LM Studio, MLX.
  • Ollama: turnkey local LLM serving on top of Llama.cpp. ollama run llama3 and you have a model.
  • MLX (Apple): native Apple Silicon serving, GGUF and safetensors.
  • SGLang: fast emerging, RadixAttention for shared prefix caching. Strong for agentic workloads with repeated context.
  • Triton Inference Server: NVIDIA's general-purpose serving — multi-model, multi-framework. Heavy but production-grade.

Decision tree:

  • Self-host, max throughput → vLLM or SGLang.
  • Self-host on consumer hardware / desktop → Ollama (Llama.cpp).
  • NVIDIA enterprise stack → TensorRT-LLM + Triton.
  • Don't want to host anything → HF Inference Endpoints, Together AI, Modal, Replicate. Cost more per token but zero ops.

End-to-end recipe — fine-tune to served endpoint

Pulling it all together. Starting from the LoRA model from chapter 12:

1. Merge LoRA into base, save as safetensors: ``python model.save_pretrained_merged('llama3-mine', tokenizer, save_method='merged_16bit') ``

2. Quantize for serving (optional but recommended): - For vLLM: pip install autoawq; python -m awq.quantize llama3-mine --bits 4 --output llama3-mine-awq. - For Ollama/Llama.cpp: model.save_pretrained_gguf('llama3-mine.gguf', tokenizer, quantization_method='q4_k_m').

3. Serve: - vLLM (24GB GPU, 30+ rps): vllm serve llama3-mine-awq --quantization awq --max-model-len 4096 --gpu-memory-utilization 0.9. - Ollama (laptop / consumer): ollama create mine -f Modelfile && ollama run mine. - Modal / Replicate (no-ops): push to HF Hub, point a serverless GPU at it.

4. Front-end: any client that speaks OpenAI's API hits vLLM directly. Or wrap in FastAPI + WebSockets for streaming chat.

5. Observe: - Latency (TTFT, ITL) via Prometheus or vLLM's metrics endpoint. - Quality drift via offline replays + LLM-as-judge. - Cost per request: (GPU hourly / requests-per-hour).

This pipeline — fine-tune with Unsloth, merge, quantize, serve with vLLM, front with FastAPI, observe with Prometheus — is the entire technical stack of most modern AI startups. Six libraries, ~200 lines of glue. You now have all of it.

What to learn next

After this course, three directions branch out:

  • RAG and agents: LangChain / LlamaIndex / Haystack for retrieval-augmented systems. Tool use, function calling, multi-step reasoning. The shape of most LLM products in 2026.
  • Multimodal: CLIP / SigLIP for vision-language embeddings, LLaVA / Pixtral / Qwen-VL for chat-with-images, Whisper for speech. Same nn.Module foundation, two encoders.
  • Training at scale: FSDP / DeepSpeed / Megatron for 7B-405B training. ZeRO-3, tensor parallelism, pipeline parallelism. Ray for orchestration. Reach for these when you need to *train* a foundation model, not fine-tune one.
  • Inference performance: kernel fusion (Triton, CUDA), graph compilation (torch.compile), quantization research (FP4, INT2), and the brand-new wave of inference-time scaling (DeepSeek-R1, o1-style chain-of-thought RL).

A reasonable next month: pick a real problem at work or a side project, fine-tune a small model on it with Unsloth, serve it with vLLM, and write up the results. That's a portfolio piece that an employer or YC partner will take seriously.

Key commands

  • pip install vllm autoawq
  • vllm serve <model> --quantization awq --gpu-memory-utilization 0.9
  • ollama create mine -f Modelfile && ollama run mine
  • huggingface-cli upload my-org/my-model out/
  • python -m awq.quantize <model> --bits 4 --output <model>-awq

Exercises

Q1.Your 7B model serves at 50 tokens/sec but TTFT is 2 seconds. What's likely the bottleneck?show answer
Prefill of the input prompt — long contexts. Try chunked prefill, smaller max context, or speculative decoding to amortize.
Q2.Why does paged attention give 24× throughput vs naive batching?show answer
Naive batching pads every sequence to the longest, wasting KV-cache. Paging treats KV as virtual memory and packs sequences densely.
Q3.When choose Ollama over vLLM?show answer
Local laptop / desktop deployment, single-user, CPU+GPU mixed. vLLM wins for multi-user GPU serving at high throughput.

Check your understanding

Q1
Why does PagedAttention (vLLM) give ~24× throughput vs naive batching?
Q2
You want to ship a fine-tuned 8B model to laptop users with one click. Best engine?
Q3
What does speculative decoding optimize?