资讯动态

强化学习策略从GPU训练到RK3566实机部署的完整链路实战

发布时间:2026/9/6 11:27:56 来源:尧图企业网站定制
把训练和部署分开想是我做这个项目最开始定下的基调。NVIDIA GPU 上能顺畅跑 PPO 的强化学习策略不等于一块 RK3566 的板子也能把它伺候明白。Microduck 是个 25 厘米的小型差速底盘机器人功耗、内存、算力都被限制在了很小的范围内而我这次要做的就是让一套在 GPU 上练出来的强化学习策略最终运行在 RK3566 实机上接管真实小车的运动控制。整个过程涵盖了模型设计、ONNX 导出、RKNN 量化转换、端侧推理、控制时序整定、实机联调踩过的坑不少这篇手记就把这条从仿真到实物的完整链路拆开讲一遍。1. 为什么我把训练和部署拆成两套硬件1.1 GPU 解决的是练出来不是跑起来做强化学习训练时GPU 大部分时间在干两件事并行采样 rollout 和梯度更新。PPO 这类算法能在可接受的时间范围内收敛靠的是同时开几百甚至几千个仿真环境把大量环境的观测批量塞给 GPU让策略网络和价值网络一次性前向推理一大片数据。这个数据模式和实机上推理完全是两回事——实机上一个控制周期只需要处理一条状态Batch 大小是 1GPU 的并行能力根本发挥不出来。很多入门项目会习惯性地把 GPU 当成跑得快一点的 CPU这个理解放到实机部署上行不通。你把一个带 CUDA 依赖的训练脚本原封不动搬上 RK3566先不说内存会不会爆光是初始化 CUDA 上下文和驱动层的开销就已经让一个小型机器人的控制循环很难维持了。我当时的判断很直接GPU 只负责把策略练出来实机端换一个适合轻量推理的部署方式。这也解释了为什么英伟达 GPU 到 RK3566这个迁移动作值得认真对待——两个平台之间差的不是性能倍数而是整套软件栈和设计思路。训练端你可以随手用 PyTorch 写一个几十层的大网络但部署端的 RK3566 只有四核 Cortex-A55 CPU加一个标称 0.8 TOPS 的 INT8 NPU它能接住的模型规模和算子类型跟 GPU 端不是一个世界。1.2 RK3566 的算力账0.8 TOPS 到底能干什么RK3566 严格来说不算高端 AI SoC。CPU 部分四核 Cortex-A55主频大约 1.8 GHz内置 NPU 的 INT8 算力标称 0.8 TOPS。这个数字在 2024 年听起来可能有点寒酸但如果是部署一个小规模的 MLP 策略网络0.8 TOPS 其实是够用的。问题在于很多人在模型设计阶段没有把算力约束考虑进去。比如你在训练时用了一个含 LSTM 的策略网络状态量 256 维隐藏层 512训练时 GPU 跑得飞快导到 RK3566 上之后一次推理可能就要几十毫秒20 ms 的控制周期直接被击穿。A55 单核性能本来就不强如果还跑去跑 FP32 的矩阵乘法那基本是在用最难受的方式折腾端侧设备。所以我给 RK3566 的定位是跑一个输入维度几十、隐藏层 64~128 的 MLP配合 INT8 量化利用 NPU 把单次推理压到 1ms 上下。如果你真的需要视觉策略比如用一个轻量 CNN 处理图像也不是完全不能跑但卷积层之后的全连接层、展平操作、以及各种 reshape 算子在 RKNN 转换时很容易踩算子兼容的坑后面我会专门讲。1.3 Microduck 这个 25 cm 平台最适合验证什么25 cm 的尺寸意味着 Microduck 属于轻量级机器人整机重量也就一两公斤电机是小功率直流减速电机或小型无刷电机电池容量不大整机功耗控制在几瓦到十几瓦的范围。RK3566 这种功耗友好、接口齐全的 ARM 板放在这个平台上很合适。这个平台最有价值的地方不是性能指标而是链路验证。你可以在 MuJoCo 或 Isaac Gym 里搭建一个简化的双轮底盘模型用 PPO 训练一个策略然后把策略导出、转换、部署到 RK3566 上最后控制真正的电机让机器人在实验室地板上走起来。整个过程如果一次性跑通那你对强化学习机器人部署这件事的理解会比只看论文或者只跑仿真深得多。我遇到过不少朋友一上来就想做全向底盘、机械臂、视觉导航这些复杂任务结果连最基础的仿真里能跑 → 实机上能走都没闭环。Microduck 这样的平台恰恰是让你低成本地把整个闭环走一遍的最好选择。2. 训练侧配置与模型选择别让网络结构成为部署的定时炸弹2.1 观测与动作空间的设计决定了部署难度训练之前先把状态空间和动作空间定义清楚。这一步如果没想明白后面的部署环节一定会还账。我最后采用的是状态观测 底层 PID RL 决策层的混合结构而不是端到端输出电机 PWM。具体来说观测左轮编码器速度、右轮编码器速度、IMU 俯仰角、目标方向角误差、目标距离。动作期望加速度和转向修正量维度很低的连续值。底层RK3566 上的 PID 速度控制器负责跟踪 RL 给出的目标速度RL 只输出往哪跑、多快跑不碰 PWM 层面的高频控制。这个设计不是拍脑袋想出来的而是实机部署的刚需。端到端直接输出 PWM 的策略需要在一个非常宽的映射空间里学习电机非线性、齿轮间隙、电池电压变化这些物理量策略很容易过拟合仿真环境。而分层控制把底层高频部分交给经典 PIDRL 只需要在低维动作流形里做决策学起来简单部署时推理频率的要求也低很多。对于 25 cm 底盘来说RL 直接学目标轮速这个粒度刚刚好。输出维度小、网络可以很轻量、控制频率 50 Hz 足够RK3566 跑起来没有任何压力。2.2 PPO 训练里几个直接影响部署的 Trick用 PPO 训练这类策略网上代码很多CleanRL、rl_games 都很成熟。但训练代码跑通不等于能顺利部署有几个细节在训练阶段就要考虑部署需求。动作平滑惩罚。如果你的奖励函数里只惩罚任务目标误差不惩罚动作剧烈变化策略很容易学出一套高频抖动动作。这在仿真里损失不大一上实机就是电机嘎嘎响、齿轮磨损、IMU 被振动污染。我强烈建议在奖励里加一个温和的动作差分惩罚项同时把动作变化率做 clip让策略输出的动作在时间轴上尽量平滑。这个调整对最终部署的运动质量影响极大。观测归一化折叠。PPO 训练时通常会对观测做 running mean 和 running std 归一化。导出 ONNX 时如果你不把这组统计数据折叠进第一个线性层实机端就需要单独额外维护一套统计参数等于把一个低级但很容易出错的负担留到了部署侧。我通常的做法是把 running mean/std 直接写入第一个线性层的 weight 和 bias 里导出后部署端拿到模型就是自包含的不需要额外的前处理逻辑。确定性策略导出。训练时 Actor 输出的是高斯分布均值方差部署时应该取均值作为动作。但导出阶段如果不加处理ONNX 图里可能还带着采样节点或者方差输出结果实机上的动作带有随机噪声看起来就像策略在发疯。我建议导出一个deterministic版本只保留均值路径去掉所有随机采样节点。2.3 先想部署再定网络结构省下的是整个月的时间这是我在前一个项目里摔出来的经验教训。当时我在仿真里跑了一个大 CNN LSTM 策略效果确实好收敛快、得分高。到导出阶段才发现LSTM 引入的 Scan 算子大部分端侧编译器支持得都不好RKNN 转换直接报不支持最后只能退回去重训一个小网络。从那以后我固定了一条原则先确定端侧推理工具链能跑哪些算子再回头定网络结构。RKNN-Toolkit2 对 Conv2D、Linear、ReLU、Tanh、Sigmoid 这些基础算子的支持相对完善但 GELU、LayerNorm 的某些变体、反卷积、自定义 attention 这些就可能被拆成大量小算子转换后性能断崖式下跌。MK 这个项目里网络结构被刻意设计得非常朴素输入 23 维状态两个隐藏层第一层 128 个神经元第二层 64 个激活函数用 ReLU输出层用 Tanh 把动作压到 [-1, 1]。整个模型参数不到 2 万ONNX 导出、RKNN 转换、INT8 量化全链路没有遇到一个算子兼容性问题。这种朴素不是思想懒惰而是把部署成本放到了模型设计的第一优先级。3. 模型迁移三步走ONNX 导出、精度对比、INT8 量化3.1 torch.onnx.export 的坑位与规避模型从 PyTorch 到 RKNN 的链路通常先走 ONNX 这一站。导出的脚本不复杂但有几个细节特别容易踩雷。import torch from robot_policy import Actor model Actor.load_from_checkpoint(last.ckpt) model.eval() model.cpu() dummy_input torch.randn(1, obs_dim, dtypetorch.float32) torch.onnx.export( model, dummy_input, microduck_actor.onnx, export_paramsTrue, opset_version11, input_names[obs], output_names[action], dynamic_axes{obs: {0: batch}, action: {0: batch}}, )第一注意opset_version。不是越高越好RKNN-Toolkit2 对 ONNX 算子的支持有一个窗口opset 11 通常比较稳14 之后部分算子可能在转 RKNN 时直接报不支持。建议先查你用的 RKNN 工具链版本支持的 opset 范围再写导出参数。第二导出前model.cpu()是必须的。如果模型还挂在 GPU 上ONNX 文件里的 Constant 节点可能保存了 CUDA tensor后续转换工具在纯 CPU 环境下加载时会报错。这一步很多人漏掉然后莫名其妙在转换阶段找不到原因。第三实机上如果固定每次推理一条状态导出时直接把 batch 固定为 1不要开 dynamic_axes。固定的 batch 尺寸可以让编译器/优化器做更多常量折叠推理性能更好。导出完成后用onnx.checker.check_model验证一遍接着上onnx-simplifier做图简化python -m onnxsim microduck_actor.onnx microduck_actor_sim.onnxonnx-simplifier 会把图中一堆冗余的 Shape、Gather、Unsqueeze 节点干掉这个操作能显著提高 RKNN 转换成功率。我们实测下来不简化直接转 RKNN 时偶尔会碰到一些奇奇怪怪的算子报错简化之后这些问题少了一大半。3.2 在 GPU 机器上做一次仿真一致性对照ONNX 转换完之后先别急着往 RK3566 上搬在训练机上先做一个精度对照实验——这能帮你判断整个转换链路有没有引入明显失真。我用训练时记录的一部分 eval 数据保存了大概 2000 条观测-动作对然后用 ONNX Runtime 加载转换后的模型逐个对比输出import onnxruntime as ort import numpy as np sess ort.InferenceSession(microduck_actor_sim.onnx, providers[CPUExecutionProvider]) max_diff 0.0 for obs, ref_action in eval_dataset: onnx_action sess.run(None, {obs: obs[np.newaxis, :]})[0][0] max_diff max(max_diff, np.abs(onnx_action - ref_action).max()) print(max diff:, max_diff)这个max_diff是很有价值的指标。对一个小型 MLP 来说FP32 ONNX 和 PyTorch 的计算结果一般相差在 1e-4 以下。如果这个值突跳到 0.01 以上十有八九是网络里某个自定义操作或者 BatchNorm 折叠出了问题。这时候再往下一步走就是浪费时间回头排查模型才是正事。这个步骤一定在 GPU 训练机上做因为 eval_data 就是从你的训练环境里生成的。不要在 RK3566 上临时造数据做对比那会引入太多额外变量。3.3 INT8 量化收益明显但校准集不能凑合RK3566 的 NPU 主要加速 INT8 量化模型。同样的一个 3 层 MLP实测下来推理方式单次推理延迟典型抖动备注ONNX Runtime CPUFP324~6 ms中等小模型能跑但延迟偏高LiteRT CPUINT83~5 ms中等需要先把 ONNX 转 TFLiteRKNN NPUINT80.8~1.2 ms低转换最麻烦但效果最好我的控制周期是 20 ms50 Hz 的频率。如果策略推理用 CPU 跑 4~6 ms加上传感器读取、电机通信、日志记录整个周期会非常紧凑稍微有点调度抖动就容易超时。NPU 推理 1 ms 之后主循环的余量大了很多这才是结构化设计的余量考量。量化的代价是精度损失。动作范围是 [-1, 1] 的连续值INT8 只有 256 个档位每一步动作的量化误差可能在 0.01 量级。对于底层有 PID 速度环的架构来说这个误差可以通过 PID 的平滑作用抵消掉影响不大。但如果你直接端到端输出 PWM量化误差有可能引起电机低频抖动。量化校准集这个事比很多人想的重要得多。校准数据的分布如果覆盖不全RKNN-Toolkit 在对 activation 做 min/max 估计时就会有偏差量化后动作可能整体偏小、或者出现截断。我后来直接用训练 rollout 的 replay buffer 数据随机采样了 1000 条轨迹覆盖直线、转弯、急停、加速各种工况重新量化之后输出分布明显正常了。一句话校准集要代表真实运行时可能遇到的状态分布不能随便找几条数据凑数。4. RK3566 实测环境搭建与推理性能摸底4.1 上电后别急着跑模型先把系统资源搞清楚RK3566 板子到手固件刷好、系统起来之后我做的第一件事不是装推理框架而是清点系统资源。用htop看 CPU 频率是否达到标称的 1.8 GHz还是默认锁在低功耗状态free -h看还剩多少内存cat /sys/class/misc/rknpu/version确认 NPU 驱动是否正常。很多 RK 板子的官方固件默认开启了省电策略A55 主频可能只有 1.0 GHz 甚至更低。如果你不调整 governor推理延迟会平白无故多出一倍。我习惯把 CPU governor 调到performance或者直接用cpupower固定频率。功耗会高一点但实时控制最怕的是频率漂移导致的推理时间波动——你宁可让推理稳定地在 1 ms 浮动也不希望它忽快忽慢像过山车。还有一步容易被忽略把控制主线程绑到固定的 CPU 核上并提高优先级。RK3566 是四核 A55系统后台有很多杂七杂八的进程。如果控制线程被调度到不同核上缓存命中率、中断响应都会受影响。用sched_setaffinity把主循环绑到一个核上效果立竿见影。4.2 RKNN 转换算子支持的边界在哪里Rockchip 的转换工具是 RKNN-Toolkit2需要注意它和训练机的 Python 版本匹配。我建议在独立虚拟环境里安装不要污染你训练用的 PyTorch 环境。转换脚本看起来很简单from rknn.api import RKNN rknn RKNN() rknn.config(target_platformrk3566, quantized_dtypeasymmetric_quantized-8) ret rknn.load_onnx(modelmicroduck_actor_sim.onnx) if ret ! 0: raise RuntimeError(load onnx failed) ret rknn.build(do_quantizationTrue, datasetcalib_dataset.txt) if ret ! 0: raise RuntimeError(build failed) ret rknn.export_rknn(microduck_actor.rknn) if ret ! 0: raise RuntimeError(export failed)dataset文件里写的是每行一个校准数据的路径npy或txt格式都支持。build 阶段如果遇到不支持的算子会报Unsupported operator。这时候不要硬着头皮换模型应该回到导出的 ONNX 图上做算子层面的替换。我遇到的真实情况是ReLU、Tanh、Conv、MatMul 这些算子 RKNN 都认但某些 LayerNorm 的变体、或者 ONNX 图里自动生成的Gemm转MatMulAdd组合偶尔会在特定版本的工具链上出问题。解决办法很朴素——尽量使用基础算子不给转换工具留纠结的空间。补充一条如果 NPU 转换实在过不去也可以退回到 CPU 推理。RK3566 上装 ONNX Runtime CPU EP加载 FP32 的 ONNX 模型直接跑小模型延迟不会太离谱。但 CPU 推理的延迟会随系统负载波动而且模型一稍微变大就线性恶化不是长久之计。走 NPU 依然是推荐的只是你需要提前确认算子兼容性。4.3 CPU 与 NPU 延迟实测我做了三组对比实验用的是同一个模型输入 23 维隐藏层 12864输出 3 维动作。结果上面表格里已经列了。这里重点说说如何解读这些数字。CPU 4~6 ms 的推理已经不算慢了对于纯状态输入的小 MLPA55 的性能其实比想象中好。但如果你的控制线程里同时要做传感器融合、PID 计算、日志序列化、无线通信4~6 ms 会叠加成可观的周期占用留给主循环的余量很薄。NPU 的 0.8~1.2 ms 让整个系统的时序设计从容太多。RKNN-Toolkit 有性能分析器你直接输入模型路径和目标平台就能预估各算子在推理过程中的耗时分布。这个工具非常值得提前用起来可以在写完整控制程序之前就先判断这条路能不能走通而不是等整机联调才发现延迟超了。4.4 我最终选择的端侧推理方案最终我走的是C librknnrt直接加载.rknn模型的路线而不是在 RK3566 上用 Python 包一层 rknn-toolkit2 runtime。原因很简单Python 的 GIL 和解释器调度对实时控制来说不可预测。虽然 Python 也可以调 RKNN runtime但每次推理的 API 往返、内存申请、垃圾回收都可能带来额外抖动。C 接口下模型加载一次输入输出 buffer 提前分配好每次推理就是rknn_inputs_set → rknn_run → rknn_outputs_get干净利落。控制主循环用 C 写传感器读取、状态拼接、推理、动作下发、日志记录全部在同一个 20 ms 周期内完成。这样整个系统的实时性才能有保障。5. 把推理接进关节控制回路时序、滤波与节流保护5.1 50 Hz 策略和底层 500 Hz 电流环怎么配合RL 策略推理频率通常是低频的20 Hz~50 Hz 这个数量级。但 Microduck 的电机底层控制需要 500 Hz 甚至更高频率的速度/电流环。这两者之间不是一个直接相等的关系中间需要一个缓冲机制。我设计的层次是顶层 RL 策略 50 Hz 运行一个 20 ms 周期内产出一个目标速度指令这 20 ms 内底层 PID 以 500 Hz 的频率运行把目标速度按斜坡逐步逼近策略没有更新的中间时刻底层 PID 继续维持当前的斜坡输出不会跳变。这样做的好处显而易见即使 RL 推理偶尔慢了一次电机收到的控制量不会瞬间突变不会出现策略一更新小车就猛冲的恐怖场景。斜坡限幅相当于给动作变化上了一道物理保险让端到端的信号在时间维度上平滑下来。这个设计对 RK3566 的 CPU 资源也是一种优化。底层 500 Hz 的控制循环可以在另一个核上跑RL 推理在 NPU 上跑两个循环解耦相互不阻塞。5.2 状态估计别把原始传感器数据直接丢给网络训练仿真里的观测是干净的、无噪声的实机上你得到的是带混响的现实。如果把编码器读到的一串原始脉冲计数和 IMU 的原始角速度直接拼进状态向量策略很可能进入训练时从未见过的分布外区域表现会非常奇怪。IMU 的零漂和振动噪声是最典型的坑。Microduck 的电机一启动整个底盘的振动会把陀螺仪信号搅得乱七八糟。我在实机上给陀螺仪加了一个轻量的低通滤波加速度计加滑动平均。注意滤波不能过度相位滞后太严重会让 RL 觉得状态总是慢半拍等于变相增大了系统延迟。另一个更大的坑是积分漂移。如果你在训练时的观测里包括全局坐标位置实机上靠轮速编码器积分而来的全局坐标会越走越偏。我解决的办法很干脆训练时就不让全局位置出现在观测空间里只用相对量——相对于目标的方向误差、当前轮速、目标距离这些量不依赖长时积分天然适合 sim-to-real 迁移。5.3 Fail-safe 与跌倒保护上实机前先写保护逻辑实机联调安全第一智能第二。我第一次让 Microduck 下地跑的时候保护逻辑写得不够完善小车撞上桌子腿电机堵转了大约两秒驱动板发烫严重。从那之后我把保护拆成三层输出限幅策略输出的动作在传给电机之前先经过 clip任何超出物理边界的值一律截断。看门狗主循环每 20 ms 必须喂狗。一旦超过 100 ms 没有更新策略输出系统自动判定推理异常电机进入零速状态。状态异常检测IMU 检测到俯仰角或横滚角超过阈值比如大于 60 度立即切断功率并记录日志避免机器人翻倒后电机还在空转。这套保护逻辑的核心是宁可停机不可失控。RL 策略在训练分布之外的行为是未知的你不能假设它遇到没见过的状态时会给出温和反应。给硬件留一条保命路径是实机部署的底线。5.4 一个典型的 20 ms 控制周期长什么样下面这个伪代码片段展示了 Microduck 在 RK3566 上实际跑的主循环结构while (running) { uint64_t start_us get_time_us(); // 1. 读取传感器 imu_read(imu_data); encoder_read(wheel_data); // 2. 组装状态向量 float obs[OBS_DIM]; build_obs(obs, imu_data, wheel_data, target_state); // 3. 策略推理 (RKNN NPU) rknn_inputs_set(ctx, input_num, inputs); rknn_run(ctx, nullptr); rknn_outputs_get(ctx, output_num, outputs, nullptr); float *action (float *)outputs[0].buf; // 4. 限幅 斜坡 clip_action(action, -max_action, max_action); apply_ramp(action, last_action, 0.1f); // 5. 下发到底层 PID motor_set_target(action[0], action[1], action[2]); // 6. 看门狗喂狗 日志 watchdog_feed(); log_packet(obs, action, get_time_us() - start_us); // 7. 严格睡眠到下一个周期 sleep_until_next_period(start_us, 20000); // 20ms }第 7 步是最容易被忽视的。直接调usleep(20000)或者sleep(0.02)出来的实际周期是推理耗时 传感器耗时 20ms真实频率可能只有 40 Hz 甚至更低而且漂移越来越严重。正确做法是记录本周期起始时间计算距离下个周期起点还有多少空闲然后精确 sleep 到那个绝对时间点。这样 50 Hz 的控制频率才是准的。6. 实机联调踩坑记录从仿真能跑到地上能走6.1 第一类坑端侧推理时间抖动导致的控制不稳实机第一次下地我观察到轮速指令上出现了周期性毛刺频率和策略更新频率差不多。当时心里就咯噔一下——仿真里动作明明是平滑的到实机怎么会抖成这样。排查链路是这样的打印控制周期日志发现实际周期不是稳定的 20 ms而在 18~30 ms 之间跳查看每个环节的耗时传感器读取和 RKNN 推理都算稳定但日志编码偶尔会拖到 8 ms 以上继续定位发现是日志打印用的printf在转储到串口时被阻塞了CPU 被长时间占住解决方法是把日志改成双缓冲单独开一个低优先级线程负责发送主循环只往 ring buffer 里塞数据。这个坑给了一个非常深刻的教训在实时控制程序里直接调printf往外吐数据是非常奢侈的行为。日志记录要和生产代码解耦否则一个小小地串口阻塞就能让你的控制周期乱跳。6.2 第二类坑量化后动作值整体偏小RKNN 量化模型第一次上实机小车的动作幅度明显比 FP32 模型小走起来一副没吃饱饭的样子。明明转的是同一个 ONNX差别怎么会这么大最后定位到是校准集覆盖不足。最初我只拿了一段直线行走的数据做量化校准这条数据里动作基本在 0 附近activation 的 min/max 被一个稀有状态拉得很开导致量化步长变大真正有区分度的信号区段被压缩得几乎没有分辨率。解决方法是把训练 rollout 里一段完整的轨迹文件拿来做校准里面覆盖了直线、转弯、急停、加速、减速各种工况。重新量化之后动作分布又和 FP32 版本贴近了。这件事再次印证了量化校准集和训练数据一样也要讲分布覆盖。否则你就是在用一个拍脑袋的 min/max 去近似整个激活分布。6.3 第三类坑仿真里的关节限位和实机物理相差太远还有一个很隐蔽的问题仿真里训练的转角范围设得比实机宽很多实机遇到障碍物时策略给出的转角请求已经超出了电机物理能力的上限。原因在于仿真里电机输出没有加严格的饱和和死区约束电池电压下降导致的最大力矩变化也没有模拟。实机低电量时同样的动作请求会出现电机饱和实际效果和仿真预期差了十万八千里。修复方式是在仿真环境里把电机输出做更严格的物理饱和建模同时把训练过程中的输出 clip 到和实机一致的物理范围。这一步不是可有可无的参数微调而是影响 sim-to-real 迁移效果的关键物理真实性。训练环境的物理真实程度直接决定了策略在实机上能走多远。6.4 快速仿真到现实差距评估表联调结束后我整理了一份自查清单现在每次做新的 RL 实机项目都会先过一遍环境项仿真设置实机情况是否需要修正电机转矩/转速限制设定宽松有限且随电量变化必须修正地面摩擦系数单一值随时间、材质变化用随机化训练传感器噪声可忽略明显加噪声注入控制频率波动固定 50 Hz有抖动用周期补偿机体重心偏移精确电池位置有偏差适当随机化动作输出频率每步更新底层保持限幅斜坡这个表格看起来很基础但它恰恰是很多强化学习项目在实机上翻车的根源。你的推理框架优化得再好如果训练环境离实机太远最后都会在地上能走这一步原形毕露。做完 Microduck 这个项目我最大的感触是RL 机器人落地拼的不只是算法和算力而是训练、导出、推理、控制这几段链路能否作为一个整体被工程化地对待。从英伟达 GPU 到 RK3566 实机中间每一步都可能成为瓶颈但只要每一步都留出验证手段、记录足够的数据这个链路完全可以复现。如果你正在做类似项目建议先把训练环境的物理真实性、模型结构的部署友好度、端侧推理的周期稳定性这三件事钉死剩下的问题都会在这个框架下慢慢解决。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价