强化学习机器人控制实战:从仿真环境搭建到真机部署的完整链路
1. 从摔跟头到走稳路强化学习到底在解决什么问题机器人学走路这件事乍一看是个机械问题实际上是个决策问题。你给它装再好的电机、再精密的减速器如果控制策略不对它照样走两步就趴下。传统做法是工程师手动建模算出质心轨迹、规划关节角度、设计PID控制器跟踪轨迹。这套方法在结构化环境里能用但一旦地面有坡度、有碎石、有突发扰动模型就不准了机器人立刻露馅。强化学习换了个思路不让工程师告诉机器人每一步该怎么迈而是让机器人自己去试走对了给奖励摔了给惩罚反复迭代之后它自己摸索出一套能走稳的策略。这个过程像教小孩骑车——你没法用公式描述平衡感但小孩摔几次之后身体自己就学会了。我最初接触这个方向时最大的困惑是仿真里走得挺好一到真机就废。后来才明白问题出在试错成本上。仿真里摔一万次无所谓真机上摔一次可能就损坏硬件。所以整个实战拆解的核心其实是围绕如何高效、安全地完成试错来展开的。这篇文章适合谁看如果你是有Python基础、想入门机器人控制的学生或工程师或者你已经了解强化学习的基本概念但不知道怎么落到机器人上那接下来的内容会帮你把从仿真环境搭建到策略部署的完整链路走一遍。我会重点讲那些文档里不写、但实际调试中一定会遇到的问题。2. 仿真环境搭建为什么MuJoCo和PyBullet是绕不开的起点2.1 物理引擎选型的核心考量机器人强化学习的第一步不是写算法而是搭一个靠谱的仿真环境。物理引擎的选择直接决定了你后续训练的效率上限。目前主流方案有三个MuJoCo、PyBullet、Isaac Sim。我实际用下来入门阶段首选MuJoCo或PyBullet原因很直接——轻量、API友好、社区资源多。MuJoCo的接触动力学求解精度高特别适合足式机器人这种需要频繁处理地面接触的场景。它的mj_step函数内部用的是凸优化求解器能比较真实地模拟摩擦锥和接触力。PyBullet的优势在于渲染和可视化更直观调试时能直接看到机器人的受力箭头和接触点对理解策略行为帮助很大。Isaac Sim虽然渲染逼真、支持大规模并行训练但它对显卡要求高安装配置也复杂新手容易被环境问题卡住好几天。我的建议是先用MuJoCo把算法跑通等策略在仿真里稳定了再考虑迁移到Isaac Sim做大规模并行加速。2.2 搭建一个最小可用的训练环境以MuJoCo为例搭建一个四足机器人行走环境的核心步骤import gymnasium as gym import mujoco # 加载MuJoCo自带的四足环境 env gym.make(Ant-v4, render_modehuman) # 查看观测空间和动作空间 print(观测维度:, env.observation_space.shape) # 通常27维 print(动作维度:, env.action_space.shape) # 通常8维每条腿2个关节Ant-v4的观测空间包含躯干位置、姿态四元数、各关节角度和角速度、以及接触力信息。动作空间是8个关节的目标角度增量。奖励函数默认包含前进速度奖励、生存奖励、控制代价惩罚和姿态惩罚。这里有个容易忽略的细节默认奖励函数的权重是手工调出来的不一定适合你的任务。比如你想让机器人走得更稳而不是更快就需要把姿态惩罚的权重调大。我一般会先把奖励函数拆开看每一项的贡献用TensorBoard记录训练过程中各分量的变化这样才能判断策略到底在优化什么。2.3 域随机化让仿真到现实的鸿沟变窄仿真和现实的差距主要来自几个方面质量参数不准、摩擦系数不准、电机响应延迟、传感器噪声。域随机化Domain Randomization的思路是在训练时随机扰动这些参数让策略学会适应参数变化从而在真机上也能泛化。具体操作是在每个episode开始时随机采样一组物理参数import numpy as np def randomize_env(env): # 随机化躯干质量±20% body_mass env.model.body_mass body_mass[1] * np.random.uniform(0.8, 1.2) # 随机化地面摩擦系数 geom_friction env.model.geom_friction geom_friction[:, 0] * np.random.uniform(0.5, 1.5) # 随机化电机增益 actuator_gain env.model.actuator_gainprm actuator_gain[:, 0] * np.random.uniform(0.9, 1.1)注意域随机化的范围不能太大否则策略会学得过于保守在真机上反而表现僵硬。我一般从±10%开始逐步扩大到±30%观察策略性能的变化曲线。3. 算法选型PPO、SAC、TD3在机器人控制中的真实表现3.1 为什么PPO是机器人行走任务的首选PPOProximal Policy Optimization在机器人控制任务里几乎是默认选择。原因有三第一它是在线策略算法可以直接用仿真环境产生的最新数据更新不需要维护经验回放池第二它的裁剪机制让更新步长可控训练过程相对稳定第三它对超参数不那么敏感学习率和裁剪系数在合理范围内都能收敛。我在四足机器人行走任务上对比过PPO和SAC。PPO在200万步左右能达到稳定行走SAC虽然样本效率更高约100万步但训练曲线波动大偶尔会出现策略崩溃——机器人突然学会原地打转或者向后走。对于需要反复调试的工程项目PPO的稳定性比样本效率更重要。PPO的核心超参数配置参数推荐值说明学习率3e-4配合线性衰减裁剪系数0.2控制策略更新幅度GAE lambda0.95优势估计的偏差-方差权衡折扣因子0.99考虑约100步的长期回报每批步数2048每次更新采集的样本量训练轮数10同一批数据重复利用次数3.2 SAC和TD3的适用边界SACSoft Actor-Critic的优势在于最大熵框架策略会保持一定的随机性这在探索阶段很有用。但机器人行走任务的动作空间通常是连续的而且对动作平滑性要求高SAC的随机策略会导致关节抖动真机上表现为电机发热和机械磨损。TD3Twin Delayed DDPG通过双Critic网络和延迟更新解决了Q值过估计问题在机械臂抓取任务上表现不错。但它的确定性策略在行走任务中探索能力不足容易陷入局部最优——比如学会用三条腿跳着走虽然能前进但姿态很难看。我的经验是足式机器人行走用PPO机械臂操作任务可以试SAC或TD3具体看任务对动作平滑性和探索效率的要求。3.3 从零实现PPO的关键代码段import torch import torch.nn as nn class ActorCritic(nn.Module): def __init__(self, obs_dim, act_dim, hidden256): super().__init__() self.actor nn.Sequential( nn.Linear(obs_dim, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, act_dim) ) self.critic nn.Sequential( nn.Linear(obs_dim, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, 1) ) self.log_std nn.Parameter(torch.zeros(act_dim)) def forward(self, obs): mean self.actor(obs) std self.log_std.exp() return mean, std提示log_std初始化为0意味着初始策略的标准差为1探索范围较大。如果训练初期机器人动作过于剧烈可以把log_std初始化为-1让初始策略更确定。4. 奖励函数设计决定机器人学会什么的关键4.1 奖励塑形的核心原则奖励函数是强化学习里最像玄学的部分但它其实有章可循。核心原则是奖励要引导机器人完成目标同时不能让它找到作弊路径。比如你只奖励前进速度机器人很快会发现向前摔倒也能获得高速度奖励因为摔倒瞬间躯干前冲速度很大。我设计奖励函数时通常包含四类项任务奖励前进速度、目标到达、姿态保持生存奖励每存活一步给固定奖励鼓励机器人不摔倒惩罚项关节力矩过大、动作变化率过大、躯干倾斜过度约束项关节角度超出限位、接触力过大一个实际可用的四足行走奖励函数def compute_reward(obs, action, prev_action): # 前进速度奖励 forward_vel obs[0] # 假设obs[0]是x方向速度 reward_forward 1.5 * forward_vel # 生存奖励 reward_alive 0.5 # 姿态惩罚躯干倾斜 roll, pitch obs[1], obs[2] reward_orientation -0.8 * (roll**2 pitch**2) # 动作平滑惩罚 reward_smooth -0.01 * np.sum((action - prev_action)**2) # 关节力矩惩罚 reward_torque -0.0005 * np.sum(action**2) total reward_forward reward_alive reward_orientation reward_smooth reward_torque return total4.2 奖励权重的调参经验权重调参没有万能公式但有一个实用的流程先只保留任务奖励和生存奖励让机器人学会基本前进然后逐步加入姿态惩罚和动作平滑惩罚每次加入后观察训练曲线是否还能收敛。我踩过的一个坑是一次性把所有惩罚项加进去结果机器人学会了站着不动——因为不动就不会有姿态变化惩罚最小生存奖励照拿。解决办法是让生存奖励随时间衰减或者设置一个最小前进速度阈值低于阈值不给生存奖励。另一个经验是奖励的尺度要统一。如果前进奖励是1.5姿态惩罚是-0.8那姿态惩罚的梯度信号会被前进奖励淹没。我一般会把所有奖励项归一化到[-1, 1]区间然后通过权重系数调节相对重要性。4.3 课程学习从简单到复杂的训练策略直接让机器人在复杂地形上训练大概率学不出来。课程学习Curriculum Learning的思路是先易后难先在平地上学走再在轻微起伏地面上微调最后在随机台阶和斜坡上泛化。具体实现可以维护一个地形难度参数当机器人在当前难度下连续N个episode的平均回报超过阈值时提升难度class Curriculum: def __init__(self): self.difficulty 0.0 # 0到1之间 self.success_threshold 0.8 self.window 50 self.rewards [] def update(self, episode_reward): self.rewards.append(episode_reward) if len(self.rewards) self.window: self.rewards.pop(0) avg np.mean(self.rewards) if avg self.success_threshold and self.difficulty 1.0: self.difficulty 0.1 self.rewards [] # 重置窗口注意难度提升的步长要小每次提升后给机器人足够的episode适应。我一般用0.05到0.1的步长每次提升后至少训练100个episode再评估。5. 训练加速与并行化从单环境到万级并行5.1 向量化环境最直接的加速手段单环境训练PPO采集2048步需要等仿真器一步步推进GPU大部分时间在闲置。向量化环境Vectorized Environment的思路是同时跑多个环境实例把数据收集并行化。Stable-Baselines3提供了make_vec_env接口from stable_baselines3.common.vec_env import SubprocVecEnv from stable_baselines3.common.env_util import make_vec_env # 用8个进程并行跑环境 env make_vec_env(Ant-v4, n_envs8, vec_env_clsSubprocVecEnv)8个环境并行数据采集速度提升约6-7倍有进程间通信开销。如果CPU核心够多可以开到16或32个环境。但要注意环境数量增加后每次PPO更新的批量大小也要相应调整否则梯度估计的方差会变大。5.2 GPU加速仿真Isaac Gym和Brax当环境数量超过100个时CPU仿真就成为瓶颈。Isaac Gym把物理仿真放到GPU上可以同时跑几千个环境。它的核心思路是用CUDA核函数并行计算所有环境的物理步进数据直接在GPU显存里流转不需要CPU-GPU拷贝。Brax是另一个选择基于JAX实现支持自动向量化和JIT编译。它的优势是代码简洁和JAX生态无缝集成。但Brax的物理精度不如MuJoCo适合做算法验证而不是最终部署。我实际测试过MuJoCo单环境约1000步/秒Isaac Gym在RTX 3090上跑4096个环境能达到约50万步/秒。这个差距在训练复杂策略时非常关键——原本需要一周的训练可以压缩到几小时。5.3 混合精度训练与梯度累积如果GPU显存有限可以用混合精度训练AMP减少显存占用from torch.cuda.amp import autocast, GradScaler scaler GradScaler() with autocast(): loss ppo_loss(...) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()混合精度训练在PPO上通常能减少30%-40%的显存占用训练速度提升20%左右。但要注意策略网络输出的均值和标准差对数值精度敏感如果发现训练不稳定可以把策略网络的部分保持FP32。6. 仿真到现实的迁移那些仿真里学不到的坑6.1 执行器建模电机不是理想力矩源仿真里我们通常假设关节能瞬间输出目标力矩但真实电机有响应延迟、有最大转速限制、有力矩-速度曲线。如果仿真里不建模这些特性策略在真机上会出现高频抖动或者响应滞后。我一般会在仿真里加入一阶延迟模型class ActuatorModel: def __init__(self, num_joints, delay0.02, dt0.001): self.delay_steps int(delay / dt) self.buffer np.zeros((self.delay_steps, num_joints)) self.idx 0 def step(self, target_torque): self.buffer[self.idx] target_torque self.idx (self.idx 1) % self.delay_steps return self.buffer[self.idx]这个简单的延迟模型能显著减少策略在真机上的抖动。如果电机有明确的力矩-速度曲线也可以查表实现。6.2 状态估计噪声IMU和关节编码器都不完美仿真里机器人能直接获取躯干姿态的四元数真机上这个数据来自IMU融合算法存在漂移和噪声。如果策略过度依赖精确的姿态信息真机上就会失效。处理方法是在观测里加入高斯噪声def add_observation_noise(obs, noise_std0.02): return obs np.random.normal(0, noise_std, sizeobs.shape)噪声标准差根据实际传感器的数据手册确定。IMU姿态角噪声一般在0.5-2度关节编码器噪声在0.01-0.05弧度。加入噪声后重新训练策略会学会对观测噪声鲁棒。6.3 真机部署的安全策略第一次在真机上跑强化学习策略一定要做好安全措施力矩限幅在电机驱动器层面设置最大力矩防止策略输出异常值损坏机械结构急停开关物理急停按钮必须随手可及吊架保护初期用吊架把机器人吊起来只让腿接触地面防止摔倒渐进式部署先在仿真里验证再用真机但只跑低频策略逐步提高控制频率我自己的流程是仿真训练→仿真加噪声和延迟→真机吊架测试→真机低高度测试→真机全自由度测试。每一步都要记录策略的输出分布确认没有异常值再进入下一步。7. 调试与监控训练不收敛时该看什么7.1 关键指标的可视化训练过程中必须监控的指标指标正常表现异常表现与可能原因平均回报稳步上升后趋于平稳持续下降学习率过大震荡批量太小策略熵缓慢下降骤降探索不足不降任务太简单值函数损失先降后稳持续上升值函数过拟合裁剪比例0.1-0.3之间过高更新步长太大过低学习停滞动作标准差逐渐减小不减小策略没学到确定性行为用TensorBoard记录这些指标训练时开着看能提前发现大部分问题。7.2 常见失败模式与排查路径模式一机器人学会原地站立不动。检查生存奖励是否过高或者前进奖励的权重是否太低。解决办法是降低生存奖励或者设置最小速度阈值。模式二机器人学会向后走。这通常是因为前进奖励的符号定义反了或者观测里的速度方向不对。检查观测空间的定义确认x方向速度的正负号。模式三训练后期策略突然崩溃。可能是值函数过拟合或者学习率没有衰减。加入学习率线性衰减或者增大GAE的lambda值。模式四仿真里走得好真机上原地抖动。检查执行器延迟和观测噪声是否建模控制频率是否匹配。真机控制频率通常比仿真低需要在仿真里也用相同的频率训练。7.3 策略可视化与行为分析训练完之后不要只看回报曲线要把策略的行为录下来逐帧分析。我一般会记录关节角度、关节力矩、接触力随时间的变化曲线观察步态是否对称、是否有异常抖动、落地冲击是否过大。MuJoCo提供了mujoco.viewer可以实时可视化也可以用env.render()保存视频。对于四足机器人重点看对角步态是否稳定前后腿的相位差是否合理。8. 从行走延伸到其他任务这套方法还能用在哪强化学习试错这套框架不只能让机器人走路。我后来把同样的流程迁移到了机械臂抓取任务上核心变化只有三点动作空间从关节角度变成末端执行器位姿增量奖励函数从前进速度变成目标距离观测空间加入物体位姿信息。再往后多智能体场景也可以套用。比如多个机器人协同搬运每个机器人是一个智能体奖励函数里加入协作奖励和碰撞惩罚。这时候算法要从PPO换成MAPPOMulti-Agent PPO但底层的试错逻辑是一样的。如果你已经跑通了单机器人行走下一步可以试试这些方向地形自适应在奖励里加入地形平坦度感知、动态障碍避让观测里加入障碍物距离、能耗优化奖励里加入力矩平方和惩罚。每个方向都是在原有框架上做增量修改不需要推倒重来。我个人在实际操作中的体会是强化学习落地机器人算法本身只占三成剩下七成是环境建模、奖励设计和仿真到现实的迁移。把后面这三件事做扎实比换更先进的算法管用得多。

相关新闻

Python期末综合测验备考:从踩坑到拿分的完整经验

Python期末综合测验备考:从踩坑到拿分的完整经验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 5:19:24 阅读更多 →
Claude Code 模板库搭建指南:分层规则、Skills 联动与实战避坑

Claude Code 模板库搭建指南:分层规则、Skills 联动与实战避坑

我是在第三个项目里,把同一套需求分析、代码审查、重构指令重新敲到第四遍的时候,才真正意识到 claude-code-templates 这个东西的价值。之前我跟很多人一样,觉得让 Claude Code 干活不就是把需求讲清楚吗?后来发现,讲…

2026/10/17 5:19:24 阅读更多 →
Claude Code 模板体系实战:从项目规则到自动化脚本

Claude Code 模板体系实战:从项目规则到自动化脚本

我最初接触 Claude Code 的时候,跟大多数人一样,直接扔给它一个需求就开始对话。结果呢?同一个任务,今天写出来的代码风格和明天完全不同;换个项目目录,它好像把之前的东西全忘了;团队里每个人提…

2026/10/18 12:13:09 阅读更多 →

最新新闻

Agent Infra全解析:从智能体基础设施到工程实践

Agent Infra全解析:从智能体基础设施到工程实践

前几年聊AI,所有人都在盯着模型的参数规模和榜单分数,一个模型发布,刷屏的是几个基准测试的涨点。但从去年下半年开始,我明显感觉到风向变了。身边做产品的朋友,不再张口闭口“换个大模型”,而是开始问一些…

2026/10/18 12:12:18 阅读更多 →
STM32Cube_FW_F3固件包安装与HAL工程搭建避坑指南

STM32Cube_FW_F3固件包安装与HAL工程搭建避坑指南

简介:STM32Cube_FW_F3_1.11.0.zip是意法半导体为STM32F3系列微控制器推出的官方HAL封装库软件包,面向基于ARM Cortex-M4内核进行嵌入式开发的工程师与学习者,帮助其摆脱底层寄存器操作,通过标准化API快速驱动GPIO、ADC、DAC、UART…

2026/10/18 12:12:18 阅读更多 →
AI全栈开发工程师修炼指南:技术栈、转型路径与实战复盘

AI全栈开发工程师修炼指南:技术栈、转型路径与实战复盘

1. 角色定位与能力模型解读1.1 什么是AI全栈开发工程师AI全栈开发工程师这个概念,近两年被频繁提起,但很多人的理解还停留在“会调大模型接口的前端后端开发者”。我在实际参与过几个完整的AI项目之后,对这个角色的认知有了明显变化&#xff…

2026/10/18 12:12:18 阅读更多 →
GPT-6.1 Sol Ultrafast 实测:推理速度、成本与API接入全解析

GPT-6.1 Sol Ultrafast 实测:推理速度、成本与API接入全解析

最近这一个来月,我一直在跟新的模型版本较劲。GPT-6.1 Sol Ultrafast 上线那天,我刚跑完一组长上下文压测,本以为又是一次常规迭代,仔细看完文档之后才发现这代模型在推理速度和接口设计上做了些很不一样的东西。很多朋友在后台问…

2026/10/18 12:12:18 阅读更多 →
BIO NIO AIO 区别与原理:一篇文章读懂Java网络IO模型

BIO NIO AIO 区别与原理:一篇文章读懂Java网络IO模型

BIO、NIO、AIO这三个词,但凡做Java后端的人应该都见过,面试八股文里的常客,也是很多人在“阻塞、非阻塞、同步、异步”这几个概念里绕来绕去绕不清的地方。我当年刚接触Netty的时候,也在这上面吃过不少亏,后来把系统调…

2026/10/18 12:12:18 阅读更多 →
贝叶斯网络在电力故障诊断中的实战:小样本与可解释推理

贝叶斯网络在电力故障诊断中的实战:小样本与可解释推理

简介:贝叶斯网络是一种以概率图模型表达变量间因果依赖的数学框架,其核心原理是通过有向无环图与条件概率表来描述不确定性关系。在工程实践中,它尤其擅长处理小样本、高不确定性的归因问题——例如电网调度中保护动作、断路器状态与故障类型…

2026/10/18 12:11:18 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →