news 2026/4/22 2:14:16

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/17 18:49:04

微信小程序集成RMBG-2.0:移动端智能证件照制作方案

微信小程序集成RMBG-2.0&#xff1a;移动端智能证件照制作方案 1. 为什么证件照制作在小程序里一直不顺手 做摄影服务的小程序&#xff0c;或者求职类工具&#xff0c;总绕不开证件照这个需求。用户拍张照片&#xff0c;想换蓝底、白底、红底&#xff0c;再调个尺寸——听起来…

作者头像 李华
网站建设 2026/4/21 9:37:41

Chord低代码开发:Streamlit构建分析界面

Chord低代码开发&#xff1a;Streamlit构建分析界面 1. 为什么用Streamlit快速验证Chord视频分析能力 算法工程师在业务场景中经常面临一个现实问题&#xff1a;模型效果不错&#xff0c;但要让业务方直观看到价值&#xff0c;得先搭个能跑通的界面。这时候花几天时间写前后端…

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

Qwen3-Embedding-4B基础教程:Streamlit Session State管理知识库状态

Qwen3-Embedding-4B基础教程&#xff1a;Streamlit Session State管理知识库状态 本文基于阿里通义千问Qwen3-Embedding-4B大模型构建的语义搜索演示服务&#xff0c;重点讲解如何使用Streamlit Session State有效管理知识库状态&#xff0c;实现持久化的语义搜索体验。 1. 项目…

作者头像 李华
网站建设 2026/4/17 20:26:25

Git-RSCLIP在SpringBoot项目中的集成指南:构建智能图文检索API

Git-RSCLIP在SpringBoot项目中的集成指南&#xff1a;构建智能图文检索API 你是不是遇到过这样的场景&#xff1f;手里有一大堆图片&#xff0c;想找一张“夕阳下的海边小屋”&#xff0c;只能一张张翻看文件名&#xff0c;或者凭记忆去猜。又或者&#xff0c;你的应用需要根据…

作者头像 李华
网站建设 2026/4/21 10:16:17

.NET 8 + YOLOv8 + ArcFace 高性能人脸注册、识别与轨迹追踪系统

前言智能安防、人员管理等场景对身份识别需求的增长&#xff0c;一套稳定、高效、可私有化部署的人脸识别系统变得尤为重要。许多现有方案要么依赖云端服务&#xff0c;存在隐私风险&#xff1b;要么架构复杂&#xff0c;难以维护。本文推荐一个完全本地运行、基于 .NET 8 开发…

作者头像 李华
网站建设 2026/4/18 9:49:49

闭眼入! 更贴合继续教育的降AIGC平台 千笔·专业降AIGC智能体 VS 笔捷Ai

在AI技术迅猛发展的今天&#xff0c;越来越多的学生和研究人员开始借助AI工具辅助论文写作&#xff0c;以提升效率、优化内容。然而&#xff0c;随着学术审查标准的不断提高&#xff0c;AI生成内容的痕迹愈发明显&#xff0c;论文中的“AI率”问题成为许多人的隐痛。无论是知网…

作者头像 李华