ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型推理优化实战:从PyTorch到TensorRT的七步工程化落地

大模型推理优化实战:从PyTorch到TensorRT的七步工程化落地 1. 项目概述Model-Optimizer不是工具名而是一类工程实践的统称“Model-Optimizer”这个标题乍看像某个开源库或商业软件的代号但结合NVIDIA、TensorRT-LLM、vLLM、PT文件转换TensorRT等热搜词它实际指向的是大模型推理服务落地过程中围绕GPU加速器尤其是NVIDIA GPU所展开的一整套模型压缩、格式转换、运行时调度与硬件协同优化的工程方法论。它不依赖某一个具体工具而是由TensorRT、vLLM、ONNX Runtime、CUDA Graphs、FP16/INT4量化、PagedAttention、Kernel Fusion等技术模块组合而成的系统性解决方案。我做AI推理服务落地三年从最早用PyTorch原生加载7B模型跑出2.3 token/s到现在在单张RTX 4090上部署Qwen2-7B实现158 token/s吞吐、首token延迟压到87ms核心就是把“Model-Optimizer”这四个字拆解成可执行、可验证、可复现的几十个操作节点——不是调一个API就完事而是要懂显卡寄存器怎么读、CUDA Stream怎么配、显存碎片怎么清、KV Cache页怎么分。这类优化真正解决的是三个硬痛点第一是成本不可控——没优化前跑一个7B模型要租4张A10月成本2.4万优化后单卡A10就能扛住日均5000并发成本砍掉73%第二是响应不可靠——未优化模型在高并发下P99延迟跳变剧烈有时120ms有时2.3秒用户直接关网页第三是部署不可持续——模型更新一次就得重写整个服务链路新版本TensorRT一升级原来写的custom op全报错。而Model-Optimizer的本质就是把模型从“能跑起来”推进到“跑得稳、跑得省、跑得快、跑得久”。它适合三类人一是正在把自研大模型推向生产环境的算法工程师二是负责AI服务SLO保障的运维/平台工程师三是需要在边缘设备如Jetson Orin、RTX 40系列笔记本上部署轻量模型的嵌入式开发者。你不需要是CUDA专家但必须愿意打开nvidia-smi盯着显存曲线调参数愿意花两小时编译一个TensorRT engine而不是只复制粘贴pip install命令。2. 核心设计思路为什么必须放弃“一键优化”转向分层解耦式工程架构很多人看到“Model-Optimizer”第一反应是找一个万能脚本输入模型路径输出优化后engine。我试过所有标榜“全自动”的工具——包括NVIDIA官方的trtexec封装、社区版tensorrt_llm_builder、甚至某些付费SaaS平台结果无一例外要么在Qwen2-1.5B上生成的engine比原始PyTorch还慢17%要么对DeepSeek-Coder-33B的MoE结构直接报错“Unsupported layer type: MoEExpertRouter”要么生成的engine在A10上能跑在H100上启动就OOM。根本原因在于模型优化不是图像滤镜式的批量处理而是对计算图、内存布局、硬件特性和业务负载四者进行强耦合建模的过程。就像给一辆赛车改装不能只换轮胎就宣称“已优化”必须同步调整悬挂刚度、ECU点火时机、进气道流速、变速箱齿比——每个环节都影响最终圈速。我们团队最终确立的Model-Optimizer架构是五层解耦设计第0层硬件感知层——不是简单检测GPU型号而是实测PCIe带宽用nvidia-smi -q -d PCI | grep Bus Bandwidth、显存带宽用nvbandwidth工具跑GDDR6X实测、L2缓存命中率nsys profile抓取cache__inst_executed_per_1000_cycles。比如RTX 4090的PCIe 5.0 x16理论带宽128GB/s但实测模型权重加载时仅跑出73GB/s说明瓶颈在CPU侧DMA控制器这就决定了后续必须启用weight streaming而非全量加载。第1层模型语义层——解析模型结构语义区分dense层、MoE层、RMSNorm、RoPE位置编码等。TensorRT-LLM自带的model parser会把Qwen2的RMSNorm误判为LayerNorm导致量化后精度崩塌我们改用HuggingFace transformers的model.config.architectures字段手动校验onnx graph node name双保险。第2层算子融合层——不是盲目fuse所有相邻op而是按GPU SM单元特性决策。例如在H100上将Qwen2的QKV投影RoPEAttention softmax三步融合为单个kernel能减少2次global memory读写但在A10上因SM数量少、寄存器文件小强行fusion反而增加register spilling实测慢了11%。第3层内存调度层——vLLM的PagedAttention本质是把KV Cache虚拟化为离散页但页大小必须匹配GPU显存页粒度。我们发现A10默认页大小4KB而H100是64KB若沿用同一套page table配置H100上会出现大量TLB miss延迟飙升。第4层服务编排层——vLLM scheduler逻辑不是黑盒其max_num_seqs、block_size、swap_space参数必须根据业务请求分布反推。比如客服对话场景92%请求长度128但有8%长尾请求达2048若设max_num_seqs256会导致短请求排队等待长请求释放blockP95延迟恶化3倍。这种分层不是理论空谈。去年我们优化Qwen2-7B时按此架构逐层调试先用nsys确认PCIe瓶颈改weight streaming再用onnxruntime debug mode定位RMSNorm精度问题重写plugin接着在H100上测试不同fusion策略找到最优kernel组合然后根据实测显存页大小调整vLLM block_size最后用真实流量回放压测动态调节scheduler参数。全程耗时11天但最终性能提升不是线性叠加而是乘积效应——吞吐从89 token/s升至158 token/s首token延迟从112ms降至87ms显存占用从14.2GB压至10.8GB。关键在于每一层优化都可独立验证、独立回滚不会因某一层失败导致全盘崩溃。3. 核心细节解析从PT文件到TensorRT engine的七道硬核工序把PyTorch .pt模型转成TensorRT engine远不止trtexec --onnxmodel.onnx --saveEnginemodel.engine这么简单。我整理出七道必须亲手操刀的关键工序每一道都藏着让性能翻倍或归零的细节。这些步骤在官方文档里往往一笔带过但实操中踩坑率超80%。3.1 工具链版本锁死为什么TensorRT 10.2.0.11 CUDA 12.2 cuDNN 8.9.7是当前最稳组合TensorRT版本兼容性是隐形杀手。去年我们用TensorRT 10.3部署Qwen2-7B在H100上跑出158 token/s但切换到A10时engine加载失败报错“Assertion!isDynamic()failed”。查源码发现10.3新增的dynamic shape支持在A10驱动栈里触发了旧版cuBLAS的bug。最终锁定TensorRT 10.2.0.11——这是最后一个对A10/H100双平台稳定支持的版本。配套CUDA必须12.2因为12.3的nvcc编译器在生成int4 quantization kernel时会产生非法指令cuDNN选8.9.7而非最新8.9.8因后者在处理Qwen2的GroupNorm时有精度溢出bug。版本锁死不是保守而是用nvidia-smi -q -d DRIVER确认驱动版本后反向推导出的唯一安全组合。我们用docker build构建基础镜像时会把这三者哈希值写入LABELLABEL trt_version10.2.0.11 cuda_version12.2.2 cudnn_version8.9.7.76这样任何人在任何环境拉取镜像都能保证底层一致。别信“最新版最好”在AI推理领域稳定压倒一切。3.2 ONNX导出的三大禁忌shape inference、opset选择、dynamic axis定义PyTorch模型导出ONNX是第一道生死关。常见错误禁忌1用torch.onnx.export(model, dummy_input, model.onnx, export_paramsTrue)直接导出。这会让ONNX runtime无法推断dynamic batch size。正确做法是显式声明dynamic_axesdynamic_axes { input_ids: {0: batch, 1: seq_len}, attention_mask: {0: batch, 1: seq_len}, output: {0: batch, 1: seq_len} } torch.onnx.export(model, dummy_input, model.onnx, dynamic_axesdynamic_axes, opset_version18)禁忌2opset版本乱选。Qwen2的RoPE需要opset 18的ConstantOfShape和Slice新行为用opset 17会生成错误的position_ids。但opset 18又不支持某些老模型的ScatterND所以必须按模型架构查TensorRT支持矩阵。禁忌3忽略shape inference。导出后必须用onnx.shape_inference.infer_shapes_path(model.onnx)补全shape否则TensorRT parser会因维度未知报错“Cannot infer shape for node XXX”。我们写了个check脚本自动扫描ONNX graph里所有node的output_shape是否为空为空则中断流程。3.3 TensorRT builder配置的六个致命参数trtexec只是封装真正起作用的是TensorRT C API里的IBuilderConfig。这六个参数决定engine能否生成、生成多快、跑得多稳max_workspace_size不是越大越好。设4GB430在A10上够用但在H100上必须设16GB否则builder会因workspace不足跳过某些fusion。我们用nvidia-smi -q -d MEMORY | grep Total Memory * 0.3动态计算。set_flag(BuilderFlag.FP16)开启FP16必须配合set_flag(BuilderFlag.STRICT_TYPES)否则TensorRT可能在某些layer里偷偷切回FP32导致精度崩塌。set_flag(BuilderFlag.INT8)INT4量化需额外set_flag(BuilderFlag.QAT)且必须提供calibration dataset。我们用Qwen2训练集的1024个样本做calibration而非随机采样。min_timing_iterations/max_timing_iterations设为20/20避免冷启动cache干扰timing。set_memory_pool_limit(MemoryPoolType.WORKSPACE, workspace_size)与max_workspace_size呼应但更底层。add_optimization_profile(profile)必须为每个dynamic axis定义profile范围如batch_size从1到128seq_len从16到2048。漏定义会导致runtime报错“Optimization profile is not valid”。3.4 自定义Plugin开发绕过TensorRT不支持的Qwen2算子Qwen2的RMSNorm和SwiGLU在TensorRT 10.2原生不支持。有人用ONNX算子替换但精度损失超1.2%。我们选择写custom pluginRMSNorm plugin继承IPluginV2DynamicExt重写enqueue()函数用CUDA kernel实现__global__ void rmsnorm_kernel(float* input, float* output, float* weight, int hidden_size, float eps) { int idx blockIdx.x * blockDim.x threadIdx.x; if (idx hidden_size) { float sum 0.0f; for (int i 0; i hidden_size; i) sum input[i] * input[i]; float norm sqrtf(sum / hidden_size eps); output[idx] input[idx] / norm * weight[idx]; } }编译时用nvcc -archsm_80A10或sm_90H100指定compute capability生成librmsnorm.so。在builder里注册config-add_plugin_v2(plugin, plugin_size)。关键经验plugin kernel必须用float而非half计算中间值否则RMSNorm的数值稳定性崩塌。我们实测过half中间计算在Qwen2上会让PPL从7.23恶化到11.89。3.5 Engine序列化与反序列化的内存陷阱生成的engine文件不是直接load就能用。常见坑序列化时未对齐内存TensorRT要求serialized engine buffer地址8字节对齐否则deserialize失败。我们用posix_memalign(buffer, 8, size)分配内存。反序列化时context创建失败必须确保createExecutionContext()前engine已完整加载到GPU显存。用cudaMalloc分配显存memcpyHtoD拷贝而非直接用host buffer。多线程加载冲突10个线程同时deserialize同一engine会因CUDA context竞争卡死。我们用std::mutex保护deserialize过程并预热先用dummy input run一次再正式服务。3.6 vLLM集成中的TensorRT engine注入技巧vLLM默认用PyTorch backend要注入TensorRT engine需修改其model_runner.py在__init__里加载engineself.trt_engine load_trt_engine(qwen2_7b.engine)重写forward()函数当input_ids进入时调用self.trt_engine.execute_async(...)而非原生model.forward()关键是tensor shape适配vLLM的input_ids是[batch, seq_len]但TRT engine期望[batch, seq_len, hidden_size]需在forward里插入embedding lookup layer。我们用vLLM内置的get_model_config().hf_config.hidden_size获取维度避免硬编码。性能瓶颈常在数据搬运从vLLM的PagedAttention输出的key/value tensor到TRT engine输入需cudaMemcpyAsync异步拷贝否则同步拷贝吃掉30% GPU时间。3.7 模型验证的黄金三指标PPL、token/s、显存占用率生成engine后必须用三指标交叉验证PPLPerplexity用WikiText-2测试集PPL偏差5%即精度失效。我们写脚本自动对比TRT engine与PyTorch原模型的logits输出cosine similarity 0.999则reject。token/s用固定prompt长度如128测throughput但必须跑满5分钟排除cache warmup干扰。显存占用率nvidia-smi -q -d MEMORY | grep Used Memory但要注意vLLM的swap_space会占用host memory需用free -h看实际GPU显存。曾有个engine PPL合格、token/s达标但显存占用14.2GB超A10上限上线后OOM。后来发现是TRT builder没设max_workspace_sizebuilder偷偷用了16GB workspace——这提醒我们三指标缺一不可。4. 实操全流程从Ubuntu裸机到vLLMTensorRT服务的12步手把手以下是我们团队标准化的Model-Optimizer实操流程已在Rocky Linux 10、Ubuntu 22.04、Windows WSL2三种环境验证。每一步都标注了“为什么这么做”和“不做会怎样”拒绝黑盒操作。4.1 环境初始化驱动、CUDA、容器工具链的原子级安装NVIDIA驱动安装绝不用ubuntu自带的nvidia-driver-535因其对RTX 40系支持不全。从NVIDIA官网下载.run包如NVIDIA-Linux-x86_64-535.129.03.run执行sudo ./NVIDIA-Linux-x86_64-535.129.03.run --no-opengl-files --no-x-check。--no-opengl-files防止覆盖系统OpenGL库--no-x-check避免X server冲突。CUDA Toolkit安装用runfile而非deb包因deb包会强制装driver。执行sudo ./cuda_12.2.2_535.104.05_linux.run --silent --override --toolkit --samples--silent静默安装--override跳过driver检查因已装好。NVIDIA Container Toolkit安装这是docker调GPU的关键。执行curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg再curl -fsSL https://nvidia.github.io/libnvidia-container/ubuntu22.04/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list最后sudo apt-get update sudo apt-get install -y nvidia-container-toolkit。验证docker run --rm --gpus all nvidia/cuda:12.2.2-base-ubuntu22.04 nvidia-smi应显示GPU信息。提示若nvidia-smi报错“Failed to initialize NVML”八成是驱动没装好或secure boot开启。关闭secure boot或重装驱动。4.2 基础镜像构建Dockerfile的精简与加固我们不用nvidia/cuda:12.2.2-base因其含大量无用包如texlive。自建DockerfileFROM ubuntu:22.04 RUN apt-get update apt-get install -y --no-install-recommends \ python3-pip python3-dev build-essential libglib2.0-0 libsm6 libxext6 libxrender-dev \ rm -rf /var/lib/apt/lists/* COPY --fromnvidia/cuda:12.2.2-runtime-ubuntu22.04 /usr/local/cuda /usr/local/cuda ENV PATH/usr/local/cuda/bin:$PATH ENV LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRARY_PATH RUN pip3 install --no-cache-dir torch2.3.0cu121 torchvision0.18.0cu121 --extra-index-url https://download.pytorch.org/whl/cu121 RUN pip3 install --no-cache-dir tensorrt10.2.0.11 pycuda2023.1 onnx1.15.0 onnxruntime-gpu1.17.1关键点--no-install-recommends减小镜像体积37%COPY --from复用NVIDIA官方CUDA runtime避免重复下载PyTorch版本必须与CUDA 12.2匹配用cu121后缀而非cu122因CUDA 12.2对应cu121 ABI4.3 模型准备HuggingFace模型的本地化与结构校验以Qwen2-7B为例git clone https://huggingface.co/Qwen/Qwen2-7B下载模型python3 -c from transformers import AutoConfig; cAutoConfig.from_pretrained(./Qwen2-7B); print(c.architectures)确认是[Qwen2ForCausalLM]非[LlamaForCausalLM]避免误用Llama插件ls ./Qwen2-7B/pytorch_model.bin.index.json检查是否为sharded checkpoint若是则用transformers的shard_checkpoint工具合并因TensorRT不支持sharded loading。注意不要用git lfs pull因网络不稳定易中断。用huggingface-cli download Qwen/Qwen2-7B --repo-type model --revision main --include pytorch_model*.bin精准下载。4.4 ONNX导出动态batch与RoPE的精准控制写export_qwen2.pyfrom transformers import AutoModelForCausalLM, AutoTokenizer import torch model AutoModelForCausalLM.from_pretrained(./Qwen2-7B, torch_dtypetorch.float16) tokenizer AutoTokenizer.from_pretrained(./Qwen2-7B) dummy_input tokenizer(Hello, return_tensorspt).input_ids.to(cuda) # Qwen2 RoPE需固定max_position_embeddings model.config.max_position_embeddings 2048 model.config.rope_theta 1000000.0 # Qwen2专用theta torch.onnx.export( model, dummy_input, qwen2-7b.onnx, input_names[input_ids], output_names[logits], dynamic_axes{ input_ids: {0: batch_size, 1: sequence_length}, logits: {0: batch_size, 1: sequence_length} }, opset_version18, do_constant_foldingTrue )执行后用onnxsim qwen2-7b.onnx qwen2-7b-sim.onnx简化graph减少冗余op。4.5 TensorRT Engine构建从trtexec到C builder的跃迁先用trtexec快速验证trtexec --onnxqwen2-7b-sim.onnx \ --fp16 \ --workspace4096 \ --minShapesinput_ids:1x16 \ --optShapesinput_ids:8x512 \ --maxShapesinput_ids:16x2048 \ --saveEngineqwen2-7b-fp16.engine若成功再用C builder精细控制编写build_engine.cpp设置BuilderFlag.STRICT_TYPES、add_optimization_profile等编译nvcc -o build_engine build_engine.cpp -I/usr/include/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu -lnvinfer -lnvparsers -lnvonnxparser运行./build_engine qwen2-7b-sim.onnx qwen2-7b-fp16.engine关键--minShapes设为1x16最小batch和seq_len避免engine无法处理短文本。4.6 vLLM服务集成修改backend与启动参数克隆vLLM源码git clone https://github.com/vllm-project/vllm.git cd vllm修改vllm/model_executor/models/qwen2.py在forward()里注入TRT engine调用构建wheelmake wheel安装pip install dist/vllm-0.4.2-py3-none-any.whl启动服务python -m vllm.entrypoints.api_server \ --model ./Qwen2-7B \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9 \ --max-model-len 2048 \ --enforce-eager \ --dtype half \ --quantization awq \ --trt-engine-path ./qwen2-7b-fp16.engine--enforce-eager禁用CUDA Graph因TRT engine已高度优化--quantization awq启用AWQ量化与TRT INT4互补。4.7 性能压测用locust模拟真实流量写locustfile.pyfrom locust import HttpUser, task, between import json class Qwen2User(HttpUser): wait_time between(0.1, 0.5) task def generate(self): payload { model: Qwen2-7B, prompt: Explain quantum computing in simple terms., max_tokens: 512, temperature: 0.7 } self.client.post(/v1/completions, jsonpayload)启动locust -f locustfile.py --host http://localhost:8000 --users 100 --spawn-rate 10监控指标vLLM metrics endpoint/metrics抓取vllm:prompt_tokens_total、vllm:generation_tokens_totalnvidia-smi -l 1 实时记录GPU利用率、显存占用time curl http://localhost:8000/v1/completions测单请求延迟4.8 日志与监控构建可观测性闭环vLLM日志启动时加--log-level DEBUG日志输出到/var/log/vllm.logGPU监控用dcgm-exporter暴露metricsPrometheus抓取DCGM_FI_DEV_GPU_UTIL、DCGM_FI_DEV_MEM_COPY_UTIL请求追踪在api_server.py里加OpenTelemetry追踪每个request的model_forward_time、trt_execute_time、kv_cache_hit_rate告警规则当vllm:time_to_first_token_seconds{quantile0.95} 150或DCGM_FI_DEV_MEM_COPY_UTIL 95时企业微信告警。4.9 故障注入测试验证优化鲁棒性用chaos-mesh注入故障kubectl apply -f network-delay.yaml模拟网络延迟验证vLLM retry机制kubectl apply -f pod-failure.yaml随机kill worker pod验证auto-scalingkubectl apply -f stress-cpu.yaml给host打满CPU观察GPU利用率是否被抢占曾发现当host CPU 100%时vLLM的PagedAttention page allocation变慢导致P99延迟飙升。解决方案在vLLM启动参数加--worker-use-ray让worker进程绑定独立CPU core。4.10 模型热更新零停机切换enginevLLM不支持热reload engine我们用nginx做流量切分启动两个vLLM实例port 8000旧engine、port 8001新enginenginx配置upstream backend { least_conn; server 127.0.0.1:8000 weight100; server 127.0.0.1:8001 weight0; }更新时先curl -X POST http://localhost:8001/health确认新实例ready再nginx -s reload逐步调高weight至100旧实例weight降为0。全程用户无感知。4.11 安全加固限制GPU资源与模型访问GPU资源限制docker run时加--gpus device0,1 --memory16g --cpus8防止单容器吃光资源模型访问控制在vLLM api_server.py里加JWT鉴权Authorization: Bearer tokentoken由内部密钥签发敏感信息隔离.env文件不进git用k8s secret挂载环境变量名全大写加前缀VLLM_MODEL_4.12 文档沉淀生成可执行的runbook每完成一次Model-Optimizer生成Markdown runbookhardware_spec.mdGPU型号、驱动版本、PCIe带宽实测值model_config.md模型架构、hidden_size、num_layers、rope_thetatrt_config.mdbuilder参数、workspace size、dynamic axes范围vllm_config.md启动参数、scheduler tuning、metrics阈值validation_report.mdPPL对比表、token/s benchmark、显存占用截图这份runbook是团队知识资产新人照着runbook2小时内可复现90%优化效果。5. 常见问题排查21个高频故障的根因与速查表Model-Optimizer实操中83%的问题集中在环境、配置、数据三类。我把三年踩过的坑整理成速查表按现象→根因→解决步骤排列附真实报错日志片段。现象根因解决步骤真实日志片段trtexec报错“Assertion!isDynamic()failed”TensorRT版本与GPU compute capability不匹配降级TensorRT至10.2.0.11确认A10用sm_80H100用sm_90Assertion failed: !isDynamic() at tensorrt/rtSafe/safeContext.cpp:123vLLM启动报错“OSError: libcudart.so.12: cannot open shared object file”CUDA runtime库路径未注入在Dockerfile中加ENV LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRARY_PATHImportError: libcudart.so.12: cannot open shared object fileengine加载后PPL暴增logits全为nanFP16模式下RMSNorm中间值溢出在custom plugin中用float计算或加--strict-typesflagPPLinf, logits[nan, nan, ...]nvidia-smi显示GPU 0% utilization但token/s极低PCIe带宽瓶颈权重加载慢用nvbandwidth测PCIe带宽启用--weight-streamingnvidia-smi -q -d PCI | grep Bandwidth显示50GB/svLLM报错“ValueError: max_num_seqs must be 1”scheduler参数未按业务流量设置根据压测结果设--max-num-seqs256非默认128ValueError: max_num_seqs must be 1docker run --gpus all报错“docker: Error response from daemon: could not select device driver”NVIDIA Container Toolkit未安装或服务未启sudo systemctl restart nvidia-container-toolkit-daemondocker: Error response from daemon: could not select device driverQwen2 RoPE位置编码错乱输出乱码onnx导出时rope_theta未设在AutoConfig中显式设rope_theta1000000.0output\u0000\u0000\u0000...trtexec生成engine后load时报“Invalid engine”序列化buffer未8字节对齐用posix_memalign(buffer, 8, size)分配内存ERROR: INVALID_STATE: Deserialize the engine failed.vLLM P95延迟忽高忽低波动超100mshost CPU被其他进程抢占htop看CPU usage加--worker-use-ray绑定coretime_to_first_token_seconds{quantile0.95} 87ms → 213msengine在A10上OK在H100上OOMworkspace size未按显存比例设H100设--workspace16384A10设--workspace4096CUDA out of memory. Tried to allocate 2.00 GiB提示所有问题排查第一步都是nvidia-smi -q -d MEMORY看显存是否真满而非凭感觉。曾有个case显存显示98%但nvidia-smi -q -d COMPUTE显示compute utilization仅12%说明是显存泄漏非计算瓶颈。6. 实战心得那些文档里不会写的12条血泪经验这些经验来自上百次Model-Optimizer实战是文档、教程、论文里绝不会写的细节但每一条都价值千金永远用nvidia-smi -l 1盯实时显存而不是看free -hvLLM的swap_space会占用host memory但free -h显示正常GPU显存却已爆。我们曾在生产环境因此OOM三次直到加了watch -n 1 nvidia-smi --query-gpumemory.used --formatcsv,noheader,nounits实时监控。TensorRT engine文件大小≠性能优劣见过1.2GB的engine比800MB的慢37%因前者启用了过多fusion寄存器压力过大。性能只看trtexec --duration30实测结果。Qwen2的rope_theta必须设为1000000.0不是10000官方文档写10000但Qwen2实际用1000000设错会导致position_ids错位输出完全乱码。这是Qwen团队私有实现未公开。vLLM的--gpu-memory-utilization 0.9不是越高越好设0.95在A10上会因显存碎片导致OOM0.9是安全阈值。我们用nvidia-smi dmon -s u监控utilization动态调整。不要信ONNX模型的opset_version标签有些模型导出时标opset 18但实际
返回列表