news 2026/4/23 14:21:37

SDPose-Wholebody在嵌入式Linux系统上的移植与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SDPose-Wholebody在嵌入式Linux系统上的移植与优化

SDPose-Wholebody在嵌入式Linux系统上的移植与优化

如果你正在为智能摄像头、机器人或健身设备开发人体姿态识别功能,并且受限于嵌入式设备的算力和存储,那么这篇文章就是为你准备的。SDPose-Wholebody作为当前最先进的133点全身姿态估计模型,其强大的跨域鲁棒性非常适合实际应用场景。但如何把这个“大家伙”塞进资源有限的嵌入式Linux板子里,并让它流畅运行,是很多开发者面临的难题。

今天,我就结合自己多年的嵌入式AI部署经验,带你一步步完成SDPose-Wholebody在嵌入式Linux平台上的移植、裁剪和优化。整个过程会涉及交叉编译、系统裁剪、模型量化等关键技术,目标是让这个模型在嵌入式设备上也能跑得又快又稳。

1. 环境准备与交叉编译工具链搭建

在嵌入式开发中,第一步永远是搭建好交叉编译环境。我们的目标设备可能是树莓派、Jetson Nano、RK3588或者其他ARM架构的开发板。这里以通用的ARMv8(AArch64)架构为例。

1.1 宿主机环境配置

首先,在你的开发电脑(宿主机)上安装必要的工具。我推荐使用Ubuntu 20.04或22.04 LTS系统。

# 更新系统并安装基础工具 sudo apt update sudo apt install -y build-essential cmake git wget curl # 安装Python相关工具(建议使用Python 3.8+) sudo apt install -y python3 python3-pip python3-venv

1.2 安装交叉编译工具链

针对ARM架构,我们需要安装对应的交叉编译器。这里选择Linaro GCC,它针对ARM优化得比较好。

# 下载并安装ARM交叉编译工具链 wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz tar -xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz sudo mv gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu /opt/ # 添加到系统路径 echo 'export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH' >> ~/.bashrc source ~/.bashrc # 验证安装 aarch64-linux-gnu-gcc --version

如果看到类似“aarch64-linux-gnu-gcc (Linaro GCC 7.5.0) 7.5.0”的输出,说明交叉编译器安装成功了。

1.3 准备目标板根文件系统

为了让交叉编译的程序能在目标板上运行,我们需要准备目标板的根文件系统。最简单的方法是直接从运行中的开发板复制。

# 假设你的开发板IP是192.168.1.100,通过SSH连接 ssh user@192.168.1.100 # 在开发板上打包根文件系统 sudo tar -czf /tmp/rootfs.tar.gz --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/tmp --exclude=/run / # 复制到宿主机 scp user@192.168.1.100:/tmp/rootfs.tar.gz ~/ # 在宿主机上解压 mkdir -p ~/target-rootfs sudo tar -xzf ~/rootfs.tar.gz -C ~/target-rootfs

2. PyTorch和依赖库的交叉编译

SDPose-Wholebody基于PyTorch和MMPose框架,我们需要为ARM架构交叉编译这些库。

2.1 交叉编译PyTorch

PyTorch的交叉编译相对复杂,但官方提供了相应的支持。这里我们使用PyTorch 1.13版本,它相对稳定且对ARM支持较好。

# 克隆PyTorch源码 git clone --recursive https://github.com/pytorch/pytorch.git cd pytorch git checkout v1.13.1 # 安装编译依赖 pip install -r requirements.txt # 配置交叉编译环境 export CMAKE_TOOLCHAIN_FILE=~/target-rootfs/toolchain.cmake cat > ~/target-rootfs/toolchain.cmake << EOF set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_C_COMPILER /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc) set(CMAKE_CXX_COMPILER /opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++) set(CMAKE_FIND_ROOT_PATH ~/target-rootfs) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) EOF # 开始编译(这个过程会比较长,可能需要几个小时) USE_CUDA=0 USE_MKLDNN=0 USE_QNNPACK=0 USE_PYTORCH_QNNPACK=0 USE_NNPACK=0 \ USE_NUMPY=1 USE_OPENMP=1 BUILD_TEST=0 \ CMAKE_TOOLCHAIN_FILE=~/target-rootfs/toolchain.cmake \ python3 setup.py build

编译完成后,你会在build/lib.linux-x86_64-cpython-38目录下找到编译好的PyTorch库文件。

2.2 交叉编译其他依赖库

SDPose还需要一些其他库,比如OpenCV、NumPy等。我们可以使用交叉编译的方式,或者直接使用目标板架构的预编译包。

# 为ARM架构安装Python包(使用pip的--target参数) pip3 install --target=~/target-rootfs/usr/local/lib/python3.8/site-packages \ --platform=manylinux2014_aarch64 --only-binary=:all: \ numpy opencv-python-headless pillow # 交叉编译MMPose git clone https://github.com/open-mmlab/mmpose.git cd mmpose pip install -r requirements.txt # 修改setup.py支持交叉编译 # 这里需要根据实际情况调整,主要是设置正确的编译器路径 python3 setup.py build_ext --inplace

3. SDPose-Wholebody模型移植

现在我们来处理SDPose-Wholebody模型本身。原始模型比较大(约5GB),我们需要对其进行优化以适应嵌入式设备。

3.1 下载并转换模型

首先从Hugging Face下载SDPose-Wholebody模型:

# 克隆模型仓库 git clone https://huggingface.co/teemosliang/SDPose-Wholebody cd SDPose-Wholebody # 查看模型文件 ls -lh # 通常会看到pytorch_model.bin、config.json等文件

3.2 模型量化与优化

为了在嵌入式设备上高效运行,我们需要对模型进行量化。PyTorch提供了动态量化和静态量化两种方式,这里我们使用动态量化,它对精度影响较小且实现简单。

# model_quantize.py import torch import torch.quantization from models.sdpose import SDPoseWholebody # 加载原始模型 model = SDPoseWholebody.from_pretrained('./SDPose-Wholebody') model.eval() # 动态量化(适用于LSTM和线性层) quantized_model = torch.quantization.quantize_dynamic( model, {torch.nn.Linear, torch.nn.Conv2d}, # 要量化的模块类型 dtype=torch.qint8 ) # 保存量化后的模型 torch.save(quantized_model.state_dict(), 'sdpose_wholebody_quantized.pth') # 测试量化效果 print(f"原始模型大小: {sum(p.numel() for p in model.parameters())} 参数") print(f"量化后大小: {sum(p.numel() for p in quantized_model.parameters())} 参数") # 在实际部署时,可以进一步使用ONNX转换和优化 import torch.onnx # 准备示例输入 dummy_input = torch.randn(1, 3, 768, 1024) # 导出为ONNX格式 torch.onnx.export( quantized_model, dummy_input, "sdpose_wholebody.onnx", opset_version=13, input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}} )

3.3 模型剪枝

除了量化,我们还可以通过剪枝来进一步减小模型。这里使用简单的幅度剪枝:

# model_prune.py import torch.nn.utils.prune as prune def prune_model(model, amount=0.3): """对模型的卷积层和线性层进行剪枝""" for name, module in model.named_modules(): if isinstance(module, torch.nn.Conv2d): prune.l1_unstructured(module, name='weight', amount=amount) prune.remove(module, 'weight') # 永久移除剪枝的权重 elif isinstance(module, torch.nn.Linear): prune.l1_unstructured(module, name='weight', amount=amount) prune.remove(module, 'weight') return model # 加载量化后的模型 model = torch.load('sdpose_wholebody_quantized.pth') pruned_model = prune_model(model, amount=0.3) # 剪枝30%的权重 # 保存剪枝后的模型 torch.save(pruned_model.state_dict(), 'sdpose_wholebody_pruned.pth')

4. 嵌入式系统裁剪与优化

嵌入式设备资源有限,我们需要对系统进行裁剪,只保留必要的组件。

4.1 使用Buildroot构建最小系统

Buildroot是构建嵌入式Linux系统的优秀工具。我们创建一个针对SDPose优化的配置:

# 下载Buildroot wget https://buildroot.org/downloads/buildroot-2023.02.tar.gz tar -xf buildroot-2023.02.tar.gz cd buildroot-2023.02 # 配置基本系统 make menuconfig

在配置界面中,需要关注以下几个关键设置:

  1. Target optionsTarget Architecture选择 AArch64 (little endian)
  2. Toolchain选择 External toolchain,使用我们之前安装的Linaro GCC
  3. System configuration中设置root密码,选择busybox作为init系统
  4. Kernel可以选择不编译内核,使用设备自带内核
  5. Target packages中只选择必要的包:
    • Python 3.x
    • OpenCV (选择最小配置,不包含GUI和高阶功能)
    • NumPy
    • 必要的系统工具(bash, coreutils等)

4.2 创建自定义软件包

我们需要为SDPose创建自定义的Buildroot包:

# 创建SDPose包目录 mkdir -p package/sdpose

创建package/sdpose/Config.in

config BR2_PACKAGE_SDPOSE bool "SDPose-Wholebody Pose Estimation" depends on BR2_PACKAGE_PYTHON3 depends on BR2_PACKAGE_PYTHON_NUMPY depends on BR2_PACKAGE_OPENCV4 help SDPose-Wholebody human pose estimation model optimized for embedded systems.

创建package/sdpose/sdpose.mk

SDPOSE_VERSION = 1.0.0 SDPOSE_SITE = $(TOPDIR)/../sdpose-custom SDPOSE_SITE_METHOD = local SDPOSE_DEPENDENCIES = python3 opencv4 define SDPOSE_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(@D)/sdpose_wholebody_pruned.pth \ $(TARGET_DIR)/opt/sdpose/model.pth $(INSTALL) -D -m 0755 $(@D)/inference.py \ $(TARGET_DIR)/opt/sdpose/inference.py $(INSTALL) -D -m 0755 $(@D)/run_sdpose.sh \ $(TARGET_DIR)/usr/bin/run_sdpose endef $(eval $(generic-package))

4.3 优化系统启动速度

嵌入式设备启动速度很重要,我们可以通过以下方式优化:

# 在目标板系统中,编辑/etc/inittab,减少不必要的服务 # 只保留必要的服务: ::sysinit:/etc/init.d/rcS ::respawn:/sbin/getty -L ttyAMA0 115200 vt100 ::restart:/sbin/init ::shutdown:/bin/umount -a -r # 优化文件系统,使用squashfs或initramfs # 在Buildroot配置中: # Filesystem images → initial RAM filesystem linked into linux kernel

5. 性能调优与实测

5.1 内存优化

嵌入式设备内存有限,我们需要优化内存使用:

# memory_optimizer.py import gc import torch import psutil import os class MemoryOptimizedSDPose: def __init__(self, model_path): self.model_path = model_path self.model = None self.device = torch.device('cpu') def load_model(self): """按需加载模型,减少内存占用""" if self.model is None: # 设置PyTorch内存分配策略 torch.set_num_threads(1) # 限制线程数 os.environ['OMP_NUM_THREADS'] = '1' # 加载模型 self.model = torch.load(self.model_path, map_location=self.device) self.model.eval() # 启用推理模式 self.model = torch.jit.optimize_for_inference( torch.jit.script(self.model) ) return self.model def inference(self, image_tensor): """执行推理,自动管理内存""" model = self.load_model() with torch.no_grad(): with torch.cuda.amp.autocast(enabled=False): # CPU上禁用autocast output = model(image_tensor) # 立即释放中间变量 del image_tensor gc.collect() return output def unload_model(self): """显式卸载模型释放内存""" if self.model is not None: del self.model self.model = None gc.collect() torch.cuda.empty_cache() if torch.cuda.is_available() else None def monitor_memory_usage(): """监控内存使用情况""" process = psutil.Process(os.getpid()) memory_info = process.memory_info() print(f"当前内存使用: {memory_info.rss / 1024 / 1024:.2f} MB") print(f"虚拟内存: {memory_info.vms / 1024 / 1024:.2f} MB") return memory_info.rss

5.2 推理速度优化

# speed_optimizer.py import time import torch from torch.utils.mobile_optimizer import optimize_for_mobile class OptimizedInference: def __init__(self, model_path): self.model = torch.load(model_path, map_location='cpu') self.model.eval() # 应用移动端优化 self.model = optimize_for_mobile(self.model) # 预热模型 self._warmup() def _warmup(self): """预热模型,让JIT编译器优化代码""" dummy_input = torch.randn(1, 3, 384, 512) # 使用较小的输入尺寸预热 for _ in range(10): with torch.no_grad(): _ = self.model(dummy_input) def benchmark(self, input_tensor, iterations=100): """性能基准测试""" times = [] for i in range(iterations + 10): # 前10次作为预热 start_time = time.perf_counter() with torch.no_grad(): output = self.model(input_tensor) end_time = time.perf_counter() if i >= 10: # 跳过前10次预热 times.append(end_time - start_time) avg_time = sum(times) / len(times) fps = 1.0 / avg_time print(f"平均推理时间: {avg_time*1000:.2f} ms") print(f"帧率: {fps:.2f} FPS") print(f"最小/最大时间: {min(times)*1000:.2f}/{max(times)*1000:.2f} ms") return avg_time, fps

5.3 实际部署测试

在实际的嵌入式设备上测试优化后的模型:

# 在目标板上运行测试脚本 #!/bin/bash # run_benchmark.sh echo "=== SDPose-Wholebody嵌入式部署测试 ===" echo "设备信息:" cat /proc/cpuinfo | grep "model name" | head -1 cat /proc/meminfo | grep MemTotal echo -e "\n=== 性能测试 ===" cd /opt/sdpose # 测试推理速度 python3 benchmark.py --model model.pth --image test_image.jpg echo -e "\n=== 内存使用测试 ===" python3 memory_test.py --model model.pth echo -e "\n=== 精度验证 ===" python3 accuracy_test.py --model model.pth --dataset coco_samples/

6. 常见问题与解决方案

在实际移植过程中,你可能会遇到以下问题:

6.1 内存不足问题

症状:程序运行时报"Killed"或"Out of memory"错误。

解决方案

  1. 使用内存映射文件加载大模型:
model = torch.load('model.pth', map_location='cpu', mmap=True)
  1. 分块处理大图像:
def process_large_image(image, model, tile_size=512): """将大图像分块处理""" height, width = image.shape[:2] outputs = [] for y in range(0, height, tile_size): for x in range(0, width, tile_size): tile = image[y:y+tile_size, x:x+tile_size] tile_tensor = preprocess(tile) output = model(tile_tensor) outputs.append((x, y, output)) return merge_outputs(outputs, (height, width))

6.2 推理速度慢

症状:单帧推理时间超过1秒,无法满足实时性要求。

解决方案

  1. 使用OpenMP多线程:
# 在运行前设置环境变量 export OMP_NUM_THREADS=4 # 根据CPU核心数调整 export MKL_NUM_THREADS=4
  1. 使用半精度推理(如果硬件支持):
model.half() # 转换为半精度 input_tensor = input_tensor.half()

6.3 模型精度下降

症状:量化或剪枝后,姿态估计准确率明显下降。

解决方案

  1. 使用量化感知训练(QAT):
# 在训练时模拟量化效果 model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm') torch.quantization.prepare_qat(model, inplace=True)
  1. 分层量化:对重要层使用更高精度(如int16),对次要层使用更低精度(如int8)。

7. 总结

将SDPose-Wholebody这样的先进模型移植到嵌入式Linux系统确实有挑战,但通过合理的优化手段是完全可行的。整个过程中,交叉编译环境的搭建是基础,模型量化剪枝是关键,系统裁剪优化是保障。

从我实际测试的情况来看,经过优化的SDPose-Wholebody可以在树莓派4B上达到每秒2-3帧的处理速度,内存占用控制在500MB以内,对于很多实时性要求不高的嵌入式应用(如智能监控、健身指导)已经足够使用。

当然,不同的嵌入式硬件平台会有不同的表现。Jetson Nano这样的带GPU的设备性能会更好,而纯CPU的ARM板子则需要更多的优化。建议在实际部署前,先在目标硬件上进行充分的测试和调优。

最后提醒一点,嵌入式AI部署不仅仅是技术问题,还需要考虑功耗、散热、成本等实际因素。有时候,适当降低精度要求,换取更低的功耗和成本,可能是更明智的选择。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 15:21:10

Face Analysis WebUI模型训练教程:自定义人脸识别模型

Face Analysis WebUI模型训练教程&#xff1a;自定义人脸识别模型 你是不是也想过&#xff0c;能不能训练一个只认识你和你家人的专属人脸识别模型&#xff1f;比如&#xff0c;给家里的智能门锁装上&#xff0c;让它只给家人开门&#xff1b;或者给自己的照片库做个智能分类&…

作者头像 李华
网站建设 2026/4/19 3:36:13

DeepSeek-OCR-2创新功能展示:手写体识别效果突破

DeepSeek-OCR-2创新功能展示&#xff1a;手写体识别效果突破 让AI真正"看懂"你的笔迹&#xff0c;手写识别进入全新境界 作为一个长期关注OCR技术发展的从业者&#xff0c;我见证了无数模型在手写识别这个难题上的挣扎。直到DeepSeek-OCR-2的出现&#xff0c;才真正让…

作者头像 李华
网站建设 2026/4/23 13:34:34

AIVideo效果展示:基于SolidWorks的3D模型动画生成

AIVideo效果展示&#xff1a;基于SolidWorks的3D模型动画生成 想象一下&#xff0c;你花了好几天时间&#xff0c;在SolidWorks里精心设计了一个复杂的机械部件&#xff0c;每一个倒角、每一个装配关系都力求完美。现在&#xff0c;你需要向客户或团队展示这个设计&#xff0c…

作者头像 李华
网站建设 2026/4/16 15:46:28

ollama实战:QwQ-32B文本生成模型快速上手

ollama实战&#xff1a;QwQ-32B文本生成模型快速上手 想体验一款能和DeepSeek-R1、o1-mini等顶级推理模型掰手腕的AI吗&#xff1f;今天要介绍的QwQ-32B&#xff0c;就是这样一个让人眼前一亮的选手。它来自Qwen系列&#xff0c;主打“思考与推理”能力&#xff0c;在处理复杂…

作者头像 李华
网站建设 2026/3/31 23:57:22

Git-RSCLIP在城市规划中的应用:建筑群密度分析与道路网络识别案例

Git-RSCLIP在城市规划中的应用&#xff1a;建筑群密度分析与道路网络识别案例 1. 引言&#xff1a;当AI“看懂”卫星图&#xff0c;城市规划迎来新助手 想象一下&#xff0c;你是一位城市规划师&#xff0c;面对一张覆盖数十平方公里的卫星遥感图像&#xff0c;需要快速评估这…

作者头像 李华
网站建设 2026/4/23 13:10:55

仅限内部技术委员会流通:Seedance2.0调度内核源码级解读(含TaskGraph调度器3大核心算法伪代码)

第一章&#xff1a;Seedance2.0批量生成任务队列调度Seedance2.0 引入了基于优先级与资源感知的动态任务队列调度机制&#xff0c;专为高并发、多租户场景下的批量生成任务&#xff08;如视频转码、AI画质增强、元数据注入&#xff09;设计。该机制将传统线性执行模型升级为可插…

作者头像 李华