尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI工程从零开始:裸机部署到边缘推理的七层实战

AI工程从零开始:裸机部署到边缘推理的七层实战 1. 这不是“搭积木”而是亲手锻造AI系统的完整工程链“ai-engineering-from-scratch”这个标题乍看像一句技术口号但在我带过二十多个工业级AI项目、亲手从零部署过七套生产环境之后它其实是一张沉甸甸的工程路线图——不是调几个API、跑通一个notebook就叫“from scratch”而是从服务器上电那一刻起你得知道网卡驱动怎么配、CUDA版本和PyTorch二进制包为何必须严格对齐、模型权重文件在NVMe盘上的IO路径如何避免成为吞吐瓶颈、推理服务的gRPC连接池大小设为32还是64会直接影响P99延迟……这些细节文档里不写Stack Overflow上搜不到标准答案只有在凌晨三点盯着Prometheus面板里突兀跳起的GPU显存曲线时才真正理解什么叫“from scratch”。这个词组背后站着三类人一类是刚转行的工程师以为学完《动手学深度学习》就能上岗结果第一次在K8s集群里部署TensorRT引擎时发现onnxsim优化后的模型在TRT 8.6下报错“Unsupported operation: Loop”查了三天才发现是PyTorch导出时用了不兼容的torch.where变体第二类是资深MLOps负责人正被业务方催着把一个准确率92.7%的风控模型上线却发现特征服务的实时计算延迟波动超过800ms最后定位到是Redis集群主从同步的repl-backlog-size配置过小导致从节点频繁全量重同步第三类是高校研究者论文里的SOTA模型在真实数据流上F1值掉点5.3%排查后发现是线上特征归一化用的是训练集全局均值而新数据分布偏移后未做在线校准。所以这篇文章不讲“AI工程是什么”只讲“从第一行代码开始你实际要敲什么、改什么、盯什么、骂什么”。它覆盖的不是概念图谱而是你打开终端后真实面对的命令行、配置文件、监控图表和报错日志。我会用一个可复现的端到端案例贯穿全文基于ResNet-50微调的工业缺陷检测系统从Ubuntu 22.04裸机初始化到在Jetson Orin边缘设备上稳定输出12FPS推理帧率。所有步骤经我本人在三台不同配置机器上交叉验证参数值全部标注实测依据连ulimit -n该设成65535还是131072都给出压测对比数据。如果你正准备接手一个需要真正交付的AI项目而不是交一份Jupyter报告那接下来的内容就是你明天早上开会前该打印出来贴在显示器边上的操作清单。2. 内容整体设计与思路拆解为什么拒绝“黑箱式”工程路径2.1 拒绝“pip install一切”的底层逻辑很多团队启动AI项目的第一步是pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118这看似高效实则埋下三重隐患第一重是CUDA工具链污染。PyTorch官方whl包自带CUDA runtime如cu118但你的系统可能已安装NVIDIA driver 525.85.12其兼容的最高CUDA版本是11.8.0——表面看版本号匹配实则driver 525.85.12的libcuda.so.1ABI与PyTorch whl中嵌入的libcudart.so.11.8存在微小差异。我在某次产线升级中遇到过现象模型训练正常但Triton推理服务在batch_size16时偶发core dumpgdb回溯显示崩溃在cudaEventRecord调用处。最终通过LD_DEBUGlibs python -c import torch发现PyTorch加载的是whl包内自带的libcudart而非系统/usr/local/cuda-11.8/lib64/下的版本。解决方案是强制使用系统CUDApip install torch torchvision torchaudio --no-deps再手动apt install python3-torch-cuda118Ubuntu源提供。第二重是Python包依赖冲突。transformers库要求packaging20.0而某旧版kubernetes客户端要求packaging20.0。若用pip install -r requirements.txt暴力安装很可能导致K8s job控制器无法解析pod状态。我的做法是所有生产环境禁用pip install直接装业务包改用conda env create -f environment.yml其中明确指定python3.9.16、pytorch1.13.1py39_cuda117_cudnn8_0等带build string的精确版本conda的SAT求解器能自动规避冲突。第三重是硬件抽象泄漏。torch.cuda.is_available()返回True不代表GPU真能用。曾有个客户现场nvidia-smi显示GPU利用率0%watch -n1 nvidia-smi却看到显存占用缓慢爬升至95%后卡死。strace -e traceopen,openat python -c import torch; print(torch.cuda.memory_allocated())发现程序在反复open(/dev/nvidiactl)失败。根源是容器运行时没给--device/dev/nvidiactl权限而PyTorch错误地将此异常静默处理为“降级使用CPU”。因此我的工程规范强制要求任何GPU环境初始化后必须执行torch.cuda.set_device(0); torch.cuda.current_stream().synchronize()并捕获torch.cuda.OutOfMemoryError之外的OSError。提示不要相信任何“一键安装脚本”。我维护的内部工程模板里setup.sh第一行就是set -euo pipefail每个apt install后紧跟dpkg -l | grep nvidia-driver验证版本每个pip install后执行python -c import torch; assert torch.cuda.is_available(), GPU init failed。自动化不是省事而是把人工检查变成可审计的代码。2.2 “From Scratch”的真实分层从金属到服务的七层穿透真正的“from scratch”不是单一线性流程而是七层垂直穿透的工程栈每层都需独立验证层级关键验证点失败典型现象我的验证命令L1 物理层GPU风扇转速、PCIe链路宽度nvidia-smi -q -d POWER显示功耗为0Wsudo lspci -vv -s $(lspci | grep NVIDIA | head -1 | awk {print $1}) | grep -A5 LnkStaL2 驱动层nvidia-uvm内核模块加载dmesg | grep -i nvidia-uvm无输出sudo modprobe nvidia-uvm; echo $?L3 CUDA层libcudart.so符号表完整性nm -D /usr/local/cuda-11.8/lib64/libcudart.so.11.8 | grep cudaStreamCreate返回空ldd $(python -c import torch; print(torch.__file__)) | grep cudartL4 框架层PyTorch CUDA上下文隔离多进程训练时GPU显存不释放python -c import torch; ttorch.randn(1000,1000,devicecuda); print(t.device)L5 模型层ONNX算子兼容性onnxruntime.InferenceSession(model.onnx)报Unsupported op type: NonMaxSuppressionpython -c import onnx; monnx.load(model.onnx); onnx.checker.check_model(m)L6 服务层gRPC健康检查端点grpcurl -plaintext localhost:8001 list超时curl -v http://localhost:8001/v2/health/readyL7 应用层端到端推理延迟P99ab -n 1000 -c 10 http://localhost:8000/predict显示95%请求2stime curl -s -X POST http://localhost:8000/predict -H Content-Type: application/json -d {image:/9j/4AAQSkZJRgABAQAAAQABAAD/...} | wc -c这个分层不是理论模型而是我处理过的137个线上故障的根因分布统计L1-L3问题占12%多为新服务器上架场景L4-L5占63%模型迁移最痛区L6-L7占25%服务编排配置错误。因此本文的实操章节将严格按此七层展开每层提供可粘贴执行的验证命令而非泛泛而谈“检查环境”。2.3 工程决策的硬约束为什么选ResNet-50而非ViT在缺陷检测案例中我坚持用ResNet-50微调而非当前热门的ViT决策依据来自三个硬指标第一是显存带宽瓶颈。ViT的patch embedding层需将224x224图像切分为196个16x16 patch每个patch经线性投影后维度达768仅embedding层输入张量就达[1, 196, 768]而ResNet-50的首个卷积层输入为[1, 3, 224, 224]。在Jetson Orin204.8 GB/s显存带宽上实测ViT-base的forward()耗时中47%花在memcpy上而ResNet-50仅19%。这意味着当推理pipeline增加预处理resize/crop和后处理NMS时ViT的端到端延迟更易受内存墙制约。第二是量化友好度。ViT的LayerNorm层对FP16精度敏感我们在Triton中尝试INT8量化时LayerNorm输出误差达12.7%导致mAP下降8.3个百分点而ResNet-50的BatchNorm层经torch.quantization.fuse_modules融合后INT8推理mAP仅下降0.4%。这源于BatchNorm可重参数化为y gamma * (x - mu)/sqrt(var eps) beta其乘加运算天然适配INT8指令而LayerNorm的sqrt和div操作在低精度下数值不稳定。第三是调试可观测性。ResNet-50的残差块结构使梯度流清晰可追踪loss.backward()后model.layer4[2].conv3.weight.grad.norm()应约为model.conv1.weight.grad.norm()的0.3~0.5倍因深层梯度衰减。而ViT的attention权重矩阵梯度分布呈长尾model.blocks[11].attn.qkv.weight.grad.norm()常比首层高2~3个数量级难以判断是训练正常还是梯度爆炸。在产线模型迭代中可解释性直接决定故障定位速度。因此“from scratch”不等于追逐最新论文而是根据硬件约束、量化需求、运维成本做工程权衡。后续所有代码示例均基于此决策展开包括如何用torchvision.models.resnet50(weightsResNet50_Weights.IMAGENET1K_V1)加载预训练权重以及为何微调时冻结前3个stage的参数实测冻结layer1至layer3使收敛速度提升2.3倍且验证集过拟合降低17%。3. 核心细节解析与实操要点从裸机到可训练模型的17个关键动作3.1 Ubuntu 22.04系统级调优不只是装驱动那么简单在裸机上安装NVIDIA驱动绝非sudo apt install nvidia-driver-525即可。我总结出必须执行的7项系统级操作缺一不可第一禁用nouveau开源驱动。这是最常被忽略的步骤。Ubuntu默认启用nouveau它与专有驱动冲突会导致Xorg崩溃。正确操作是创建/etc/modprobe.d/blacklist-nouveau.confblacklist nouveau options nouveau modeset0然后执行sudo update-initramfs -u并重启。验证命令lsmod | grep nouveau应返回空。若忘记此步nvidia-smi可能显示GPU但torch.cuda.is_available()为False。第二配置持久化模式。默认GPU在空闲时进入低功耗状态导致首次推理延迟飙升。sudo nvidia-smi -pm 1开启持久化模式后nvidia-smi -q -d POWER显示Power Management Mode为Supported: Yes且Current为Enabled。实测开启后首帧推理延迟从1.2s降至87ms。第三设置GPU计算能力锁定。Jetson设备需固定compute capability以避免CUDA JIT编译开销。在/etc/profile.d/nvidia.sh中添加export CUDA_CACHE_MAXSIZE2147483648 export CUDA_CACHE_PATH/tmp/.nv # 锁定CC为8.7Orin export CUDA_VISIBLE_DEVICES0注意CUDA_CACHE_PATH不能设为/home/user/.nv否则多用户时缓存冲突。我曾因此导致两个模型服务互相污染PTX缓存引发cudaErrorInvalidValue。第四调整文件描述符限制。AI服务常需同时处理数百个HTTP连接和GPU流。ulimit -n默认65536不够需在/etc/security/limits.conf追加* soft nofile 131072 * hard nofile 131072 root soft nofile 131072 root hard nofile 131072并修改/etc/systemd/system.conf中的DefaultLimitNOFILE131072。验证cat /proc/$(pgrep python)/limits | grep Max open files应显示131072。第五优化NUMA内存分配。多路服务器上若CPU核心与GPU不在同一NUMA节点PCIe带宽损失可达30%。numactl --hardware查看拓扑然后用numactl --cpunodebind0 --membind0 python train.py绑定。在双路AMD EPYC系统上此操作使数据加载速度提升2.1倍。第六禁用CPU频率调节器。cpupower frequency-info若显示governor为powersave会导致训练时钟频率抖动。sudo cpupower frequency-set -g performance固定为性能模式。实测使单epoch训练时间标准差从±8.3%降至±0.7%。第七配置NVIDIA Container Toolkit。即使不用Docker也建议安装nvidia-container-toolkit因其提供的libnvidia-container能正确处理GPU设备文件权限。安装后运行sudo nvidia-ctk runtime configure --runtimedocker再sudo systemctl restart docker。验证docker run --rm --gpus all nvidia/cuda:11.8.0-devel-ubuntu22.04 nvidia-smi应正常输出。注意以上7步必须在安装PyTorch前完成。我见过太多团队先装PyTorch再调系统结果发现torch.cuda.is_available()突然失效回溯才发现是nouveau未禁用干净。系统调优不是“锦上添花”而是AI工程的基石。3.2 PyTorch环境构建精确到build string的版本控制PyTorch版本选择是“from scratch”的第一个技术十字路口。以CUDA 11.8为例官方提供三种安装方式Conda安装conda install pytorch torchvision torchaudio pytorch-cuda11.8 -c pytorch -c nvidia优势conda自动解决cudatoolkit与pytorch版本匹配cudatoolkit11.8.1与pytorch2.0.1py39_cuda118_cudnn8_0的build string严格对应。劣势conda环境体积大基础环境约3.2GB且某些企业防火墙屏蔽conda-forge源。Pip安装pip3 install torch2.0.1cu118 torchvision0.15.2cu118 --extra-index-url https://download.pytorch.org/whl/cu118优势轻量whl包仅1.8GB适合CI/CD流水线。劣势whl包内嵌libcudart.so.11.8.89若系统CUDA为11.8.0则LD_LIBRARY_PATH需优先指向whl包路径否则dlopen失败。源码编译git clone --recursive https://github.com/pytorch/pytorch git checkout v2.0.1 python setup.py install优势完全可控可启用USE_CUDA1、USE_CUDNN1、TORCH_CUDA_ARCH_LIST8.0 8.6 8.7定制。劣势编译耗时32核服务器需47分钟且需手动安装cudnn头文件。我的生产环境统一采用Conda方案原因在于其build string的确定性。例如pytorch2.0.1py39_cuda118_cudnn8_0中py39表示Python 3.9兼容cuda118表示CUDA 11.8 toolchaincudnn8表示cuDNN 8.x API_0是构建序号确保相同字符串对应完全一致的二进制验证环境是否纯净conda activate ai-env python -c import torch print(fPyTorch: {torch.__version__}) print(fGPU: {torch.cuda.is_available()}) print(fDevice: {torch.cuda.get_device_name(0)}) print(fVersion: {torch.version.cuda}) print(fCuDNN: {torch.backends.cudnn.version()}) 预期输出PyTorch: 2.0.1cu118 GPU: True Device: NVIDIA A100-SXM4-40GB Version: 11.8 CuDNN: 8302若torch.version.cuda显示11.7说明conda安装了错误的build需conda install pytorch2.0.1py39_cuda118_cudnn8_0强制指定。3.3 数据管道工程超越torchvision.transforms的工业级实践工业缺陷检测的数据管道远不止transforms.Compose([Resize, ToTensor])。我设计的生产级管道包含四个关键层第一层磁盘IO优化层。原始图像存于RAID5阵列单图平均12MB。若用PIL.Image.open()逐张读取IOPS瓶颈明显。解决方案是构建LMDB数据库import lmdb env lmdb.open(/data/defect.lmdb, map_size1099511627776) # 1TB with env.begin(writeTrue) as txn: for img_path in image_paths: with open(img_path, rb) as f: txn.put(img_path.encode(), f.read())读取时txn.get(key)比open()快4.7倍且LMDB的内存映射机制使torch.from_numpy(np.frombuffer(data, dtypenp.uint8))无需额外拷贝。第二层解码加速层。PIL解码JPEG慢且单线程。改用torchvision.io.decode_image()基于libjpeg-turbodef fast_decode(data): # data is bytes from LMDB tensor torch.ops.image.decode_image( torch.from_numpy(np.frombuffer(data, dtypenp.uint8)), modetorchvision.io.image.ImageReadMode.RGB ) return tensor.to(torch.float32).div_(255.0)实测在A100上单图解码从123ms降至28ms。第三层增强确定性层。Albumentations的随机增强在多进程下种子不同步。我的方案是class DeterministicAugment: def __init__(self, seed): self.seed seed self.aug A.Compose([ A.RandomRotate90(p0.5), A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.2) ]) def __call__(self, image, target): # 使用样本哈希作为种子确保同图同增强 key hashlib.md5(image.tobytes()).hexdigest() np.random.seed(int(key[:8], 16) ^ self.seed) augmented self.aug(imageimage.numpy(), bboxestarget[boxes].numpy()) return torch.from_numpy(augmented[image]), augmented[bboxes]第四层内存零拷贝层。避免ToTensor()的numpy.array()拷贝。直接在GPU上构建def pin_memory_collate(batch): images torch.stack([b[0] for b in batch]).pin_memory() targets [{k: v.pin_memory() for k, v in b[1].items()} for b in batch] return images, targets配合DataLoader(pin_memoryTrue, num_workers8)使GPU数据加载延迟从15ms降至2ms。实操心得不要在__getitem__里做耗时操作。我曾把图像resize放在__getitem__导致num_workers4时CPU利用率100%而GPU空闲。正确做法是预处理阶段用opencv-python-headless批量resize并存入LMDB__getitem__只做内存映射读取。3.4 模型微调策略冻结、解冻与学习率的动态博弈ResNet-50微调不是简单替换最后的FC层。我的工业实践包含三个阶段阶段一特征提取器冻结Epoch 0-10冻结layer1至layer4所有参数仅训练fc层for param in model.parameters(): param.requires_grad False model.fc nn.Sequential( nn.Dropout(0.5), nn.Linear(2048, 512), nn.ReLU(), nn.Dropout(0.3), nn.Linear(512, num_classes) )学习率设为1e-3使用AdamW。此阶段验证集准确率快速升至89.2%证明预训练特征有效。阶段二渐进式解冻Epoch 11-30按block粒度解冻Epoch 11-15解冻layer416-20解冻layer321-30解冻layer2。关键技巧是分层学习率optimizer torch.optim.AdamW([ {params: model.fc.parameters(), lr: 1e-3}, {params: model.layer4.parameters(), lr: 1e-4}, {params: model.layer3.parameters(), lr: 1e-5}, {params: model.layer2.parameters(), lr: 1e-6}, ])这样高层语义特征更新快底层纹理特征更新慢避免灾难性遗忘。阶段三全网络微调Epoch 31-50所有参数可训练但学习率衰减至1e-5并启用梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0)实测此策略使最终mAP达94.7%比全量解冻早收敛8个epoch。注意解冻时机需看验证集loss曲线。若layer3解冻后验证loss连续3个epoch上升则立即停止解冻保持layer2冻结。工程不是照搬流程而是根据数据反馈动态调整。4. 实操过程与核心环节实现从训练到边缘部署的完整流水线4.1 训练脚本的健壮性设计应对断电、OOM、网络中断生产环境训练绝不能依赖python train.py。我的train.py包含五个关键保障第一自动断点续训。每次epoch结束保存checkpoint_{epoch}.pth包含model.state_dict()、optimizer.state_dict()、scheduler.state_dict()和best_metricdef save_checkpoint(model, optimizer, scheduler, epoch, best_acc): ckpt { epoch: epoch, model_state_dict: model.state_dict(), optimizer_state_dict: optimizer.state_dict(), scheduler_state_dict: scheduler.state_dict(), best_acc: best_acc, timestamp: time.time() } torch.save(ckpt, fcheckpoint_{epoch}.pth) # 同时保存软链接到latest os.system(ln -sf checkpoint_{}.pth checkpoint_latest.pth.format(epoch))启动时自动加载checkpoint_latest.pth若不存在则从头开始。第二OOM安全退出。PyTorch OOM不抛异常而是静默终止。添加信号处理器import signal def oom_handler(signum, frame): print(OOM detected! Saving emergency checkpoint...) save_checkpoint(model, optimizer, scheduler, epoch, best_acc) exit(1) signal.signal(signal.SIGUSR1, oom_handler) # 由nvidia-smi监控触发配合外部监控脚本while true; do if [ $(nvidia-smi --query-gpumemory.used --formatcsv,noheader,nounits | head -1) -gt 38000 ]; then kill -USR1 $(pgrep -f train.py); fi; sleep 5; done第三梯度异常检测。在backward()后插入if torch.isnan(loss).any() or torch.isinf(loss).any(): print(fNaN loss at epoch {epoch}, batch {i}) # 跳过此batch不更新参数 optimizer.zero_grad() continue grad_norm torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) if grad_norm 100: print(fLarge grad norm {grad_norm} at epoch {epoch}) # 降低学习率 for g in optimizer.param_groups: g[lr] * 0.5第四分布式训练容错。使用torch.distributed.run而非torchrun因其支持--rdzv-backendc10d的弹性训练torch.distributed.run \ --nproc_per_node4 \ --rdzv-backendc10d \ --rdzv-endpointlocalhost:29400 \ --rdzv-idjob1 \ train.py当某个GPU进程崩溃其余进程等待30秒后自动重建Rendezvous。第五日志结构化。不用print()而用logging输出JSONimport logging logging.basicConfig( levellogging.INFO, format{time: %(asctime)s, level: %(levelname)s, msg: %(message)s}, handlers[logging.FileHandler(train.log)] ) logger.info({epoch: epoch, loss: loss.item(), acc: acc})便于ELK栈采集分析。4.2 ONNX导出与优化绕过PyTorch的“黑箱”陷阱PyTorch导出ONNX常失败根源在于动态控制流。我的ResNet-50导出方案第一步静态化模型。禁用torch.jit.trace改用torch.jit.script# 定义可脚本化的模型 class ScriptableResNet(nn.Module): def __init__(self, num_classes): super().__init__() self.backbone models.resnet50(pretrainedTrue) self.backbone.fc nn.Identity() # 移除FC self.classifier nn.Linear(2048, num_classes) def forward(self, x): # 确保无动态shape x torch.nn.functional.interpolate(x, size(224,224), modebilinear) features self.backbone(x) return self.classifier(features) model ScriptableResNet(num_classes3) model.eval() traced torch.jit.script(model)第二步导出ONNX。指定dynamic_axesdummy_input torch.randn(1, 3, 224, 224) torch.onnx.export( traced, dummy_input, resnet50_defect.onnx, input_names[input], output_names[output], dynamic_axes{ input: {0: batch_size}, output: {0: batch_size} }, opset_version15, do_constant_foldingTrue )第三步ONNX Runtime优化。使用onnxsim简化pip install onnxsim python -m onnxsim resnet50_defect.onnx resnet50_defect_sim.onnx再用onnxruntime-tools量化pip install onnxruntime-tools python -m onnxruntime_tools.optimizer_cli \ --input resnet50_defect_sim.onnx \ --output resnet50_defect_quant.onnx \ --optimization_level 99 \ --float16验证量化效果import onnxruntime as ort sess ort.InferenceSession(resnet50_defect_quant.onnx, providers[CUDAExecutionProvider]) input_data np.random.randn(1,3,224,224).astype(np.float32) output sess.run(None, {input: input_data}) print(Quantized inference OK)注意opset_version15是关键。Opset 12不支持NonMaxSuppression的动态输出而缺陷检测需NMS后处理。若用Opset 12导出Triton会报Operator NMS not supported。4.3 Triton推理服务部署从本地测试到K8s集群Triton配置不是写个config.pbtxt就行。我的生产配置包含六个必填字段config.pbtxt完整示例name: resnet50_defect platform: onnxruntime_onnx max_batch_size: 32 input [ { name: input data_type: TYPE_FP32 dims: [3, 224, 224] } ] output [ { name: output data_type: TYPE_FP32 dims: [3] } ] instance_group [ { count: 4 kind: KIND_GPU } ] dynamic_batching { preferred_batch_size: [8, 16, 32] max_queue_delay_microseconds: 1000 }关键参数解析count: 4在单GPU上启动4个模型实例充分利用GPU SM。实测A100上4实例比1实例吞吐高3.2倍。preferred_batch_size: [8,16,32]Triton会等待请求直到达到这些尺寸平衡延迟与吞吐。若业务要求P99100ms则设[4,8]。max_queue_delay_microseconds: 1000最大排队1ms避免小batch等待过久。本地测试命令# 启动Triton tritonserver --model-repository/models --strict-model-configfalse # 测试推理 curl -d {inputs:[{name:input,shape:[1,3,224,224],datatype:FP32,data:[[...]]}]} \ -X POST http://localhost:8000/v2/models/resnet50_defect/inferK8s部署要点使用nvidia.com/gpu: 1资源请求而非memory或cpu设置securityContext.runAsUser: 1001nvidia-docker默认用户挂载/models为PersistentVolume避免Pod重启丢失模型YAML关键段resources: limits: nvidia.com/gpu: 1 requests: nvidia.com/gpu: 1 volumeMounts: - name: model-storage mountPath: /models securityContext: runAsUser: 10014.4 Jetson Orin边缘部署从x86到ARM的跨平台编译在Orin上部署不是简单scp模型。必须重新编译第一步安装Orin专用SDK# 下载JetPack 5.1.2 SDK Manager # 在x86主机上运行选择Jetson Orin AGX目标 # 安装后得到cross-compilation toolchain export TOOLCHAIN/opt/nvidia/sdkmanager-extras/toolchains/aarch64-linux-gnu第二步交叉编译ONNX Runtimecd onnxruntime ./build.sh \ --config Release \ --build_wheel \ --update \ --build_shared_lib \ --parallel 16 \ --cmake_extra_defines CMAKE_TOOLCHAIN_FILE$TOOLCHAIN/aarch64-linux-gnu.toolchain.cmake \ --use_cuda \ --cuda_home /usr/local/cuda-11.4 \ --cudnn_home /usr/lib/aarch64-linux-gnu第三步Triton ARM镜像构建FROM nvcr.io/nvidia/tritonserver:23.05-py3
返回列表