ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

K-Means+SVM栅格分区:为蚁群路径规划搜索空间减负

K-Means+SVM栅格分区:为蚁群路径规划搜索空间减负

简介:这份PDF面向智能清洁机器人路径规划方向的学习者与研究者,聚焦复杂障碍物环境下栅格地图路径搜索效率偏低的问题,给出一种将K-Means聚类与支持向量机(SVM)结合的栅格分区思路。资源先以栅格法建立环境模型,用K-Means对障碍物栅格聚类以减少分区数量,再由SVM对聚类结果精细分割形成优化分区,最后在预处理后的地图上运行蚁群算法完成路径寻优,并附MATLAB仿真对比。压缩包共1个PDF文件,约316KB,内容涵盖地图建模、聚类步骤、SVM分类面推导与仿真结果,适合作为算法复现与论文写作的参考材料。已有277人学习,可帮助读者理解分区预处理如何缩短收敛时间、缓解蚁群算法陷入局部最优的问题。

1. 分区不是目的,是给蚁群算法“减负”

很多人第一次看到“K-Means + SVM 做栅格分区”会本能地皱眉:聚类是无监督的,SVM 是监督的,两个目标函数都不一样,硬拼在一起是不是为了发论文凑组合?但如果你真的跑过蚁群算法在 50×50 以上栅格地图上的路径规划,就会知道一个血泪经验——蚁群真正的瓶颈从来不是“找不到路”,而是搜索空间太大导致信息素在早期被均匀摊薄,收敛曲线长时间贴着高位不动。栅格地图里障碍物越碎、凹形结构越多,蚂蚁在无效栅格上反复试探的概率就越高,迭代次数被迫拉长。

这篇方法的核心结论其实很朴素:先用 K-Means 把障碍物栅格按空间邻近性聚成簇,再用 SVM 在簇与簇之间找一条最大间隔的分割面,把整张地图纵向切成少数几个区域,最后让蚁群在“区域级”而不是“栅格级”上做路径寻优。分区数量少了,蚂蚁每一步的候选集合就小了,信息素正反馈才能快速聚焦。搞懂这套机制,你就能判断什么时候该分区、分区粒度怎么定、以及为什么它比四叉树分解和 Boustrophedon 单元分解在复杂障碍物场景下更省分区数。

2. 栅格建模与 K-Means 聚类:障碍物怎么变成可计算的簇

2.1 栅格地图的坐标约定与障碍物样本集

整套方法的输入是一张二维栅格图。以左下角为原点,X 轴水平向右,Y 轴竖直向上,单元栅格边长取 1,每个栅格记录该位置是否有障碍物。仿真环境里放了 6 个障碍物,其中 1 个是凹形结构,5 个是矩形。凹形障碍物是路径规划里的经典难点——蚂蚁容易钻进凹口再退出来,信息素在凹口内反复沉积却贡献不了有效路径。

K-Means 的样本集 Ω 不是全部栅格,而是所有代表障碍物的栅格坐标。这一点很关键:聚类对象是障碍物,不是自由空间。把障碍物聚成簇,等价于把“零散的阻挡点”压缩成“几个障碍物团块”,后续 SVM 才有明确的类边界可找。初始化时给定最大簇类个数 K、最大迭代次数 Tmax、系统允许最大误差 εmax,从 Ω 中随机选 K 个栅格坐标作为初始簇心。

2.2 距离度量决定聚类形态:欧几里得距离 vs 横坐标距离

算法主体是标准 K-Means 迭代:计算每个样本点到各簇心的欧几里得距离,分配到最近簇,再用簇内样本均值更新簇心,最后算簇内误差平方和 SSE,满足|SSE_T - SSE_{T-1}| < εmax或达到 Tmax 就停。

import numpy as np def kmeans(obstacle_points, K, Tmax, eps_max): # obstacle_points: N×2 的障碍物栅格坐标 centers = obstacle_points[np.random.choice(len(obstacle_points), K, replace=False)] prev_sse = np.inf for t in range(Tmax): # 欧几里得距离分配 dists = np.linalg.norm(obstacle_points[:, None, :] - centers[None, :, :], axis=2) labels = np.argmin(dists, axis=1) # 按簇内均值更新中心 new_centers = np.array([obstacle_points[labels == k].mean(axis=0) if np.any(labels == k) else centers[k] for k in range(K)]) # 簇内误差平方和 sse = sum(np.sum((obstacle_points[labels == k] - new_centers[k]) ** 2) for k in range(K)) centers = new_centers if abs(prev_sse - sse) < eps_max: break prev_sse = sse return labels, centers

这段代码里dists的广播写法把 N 个点和 K 个簇心的距离一次算完,labels就是每个障碍物栅格的归属。注意np.any(labels == k)的空簇保护——实际跑的时候如果某个簇心被“抢空”,不处理会直接除零翻车。

真正有意思的是第二次仿真:把距离度量换成横坐标欧几里得距离,也就是只比较 x 方向差异,障碍物栅格会横向聚成 3 类。为什么这么做?因为最终目标是纵向切分地图,横向聚类让簇心在 x 轴上拉开,SVM 找分割面时才有清晰的类间间隔。用全欧几里得距离聚出来的是“团块”,用横坐标距离聚出来的是“竖条”,后者才是分区的前置形态。这是设计上的一个取舍:聚类度量不是随便选的,它要服务于下游分类器的几何假设。

3. SVM 分区:最大间隔分类面怎么变成多边形边界

3.1 从聚类标签到二分类样本

横向聚类得到 3 类障碍物簇之后,SVM 的任务不是重新聚类,而是找一条把不同簇分开的最优分类界面。线性可分情况下,分类界面写作w·x + b = 0,归一化后要求样本满足y_i(w·x_i + b) ≥ 1,分类间隔为2/||w||。要让间隔最大,等价于在约束下最小化||w||²/2。通过拉格朗日函数转成凸二次规划的对偶问题,只有a_i* ≠ 0的样本才是支持向量,最终分类函数只由支持向量决定。

这里有个容易被忽略的点:SVM 用的是聚类结果当标签,本质上是把无监督的簇归属“升格”成监督信号。簇的数量是 3,但 SVM 做的是两两或多类划分,支持向量的坐标和最优分类面在y=0、y=ymax处的交点被提取出来,作为分区多边形的顶点来源。

3.2 多边形生成与逐行 x 值比较

拿到支持向量坐标、分类面与上下边界的交点后,结合第 2 节的聚类结果生成一个多边形。然后对每一行y = {1, 2, ..., ymax}计算多边形边对应的 x 值,再比较同一 y 值下栅格中点 x 与多边形边 x 的大小关系,按大小把栅格划入不同区域,最终整图分成 3 类。

def partition_by_polygon(grid, poly_edges, ymax): # poly_edges: 每行 y 对应的多边形边界 x 值列表 region = np.zeros_like(grid, dtype=int) for y in range(ymax): xs = sorted(poly_edges[y]) # 该行所有边界 x for x in range(grid.shape[1]): # 统计栅格中点落在第几个区间 idx = sum(1 for bx in xs if x + 0.5 > bx) region[y, x] = idx return region

x + 0.5是取栅格中点,避免边界正好压在整数坐标上产生归属歧义。idx就是该栅格所属分区编号。这段逻辑看着简单,但它把 SVM 的连续分类面“离散化”成了栅格级分区表,是连接几何分类与图搜索的关键一步。

和基于四叉树的分解、基于 Boustrophedon 单元分解相比,这套方法在含大量障碍物栅格时分区数更少。原因在于四叉树会因局部障碍物反复四分,Boustrophedon 依赖扫描线遇到障碍就切,两者都对障碍物密度敏感;而 K-Means 先把障碍物压成少数簇,SVM 再找全局最大间隔面,分区数由簇结构和间隔决定,不被单个障碍物牵着走。

4. 蚁群算法在分区图上的收敛机制与参数选择

4.1 转移概率与信息素更新的完整链路

蚁群算法把 m 只蚂蚁随机放到 n 个城市(这里对应栅格节点),用禁忌表 tabuk 记录已访问点。蚂蚁 k 在 t 时刻从 i 转移到 j 的概率由信息素 τij 和启发信息 ηij 共同决定:

p_ij^k(t) = [τij]^α · [ηij]^β / Σ[τis]^α · [ηis]^β,其中ηij = 1/lij,α 是信息启发因子,β 是期望启发因子,allowedk 是禁忌表之外的可选点。一次循环结束后按τij = (1-ρ)·τij + Δτij更新,ρ 是残留系数,1-ρ 是挥发系数。Ant Cycle 模型里Δτij^k = Q/Lk,Q 是信息素强度,Lk 是第 k 只蚂蚁本次走过的总路径长度。

def ant_cycle_update(pheromone, paths, Q, rho): # paths: 每只蚂蚁的完整路径长度列表 pheromone *= (1 - rho) # 全局挥发 for path, Lk in paths: deposit = Q / Lk # 路径越短沉积越多 for (i, j) in zip(path[:-1], path[1:]): pheromone[i][j] += deposit pheromone[j][i] += deposit # 无向图双向更新 return pheromone

Q / Lk是正反馈的核心:短路径获得更高信息素,下一轮被选概率更大。分区之后,蚂蚁的候选集合被限制在区域边界和区域内自由栅格上,allowedk规模下降,同样的迭代次数下信息素分布更快收敛。

4.2 仿真参数与收敛表现

实验参数取 ρ=0.15、ε=0.1、β=2.5、m=30、q0=0.85、NCmax=50。ρ 偏小意味着挥发较慢、历史信息保留较多,配合分区后较小的搜索空间,能在 50 代内收敛。β=2.5 让启发信息权重高于信息素,前期更偏向贪心走近路,避免在分区边界附近来回震荡。q0=0.85 是伪随机比例规则里的阈值,大概率直接选最优候选,小概率按概率分布探索。

收敛曲线对比显示,分区后的蚁群在更少迭代次数内把路径长度压到低位。机制上可以这么理解:未分区时蚂蚁要在全图自由栅格上撒开,信息素被大量无效边稀释;分区后无效边被区域结构屏蔽,信息素浓度梯度更陡,正反馈起效更快。这也是为什么这套方法能同时缓解蚁群“易陷局部最优”和“大规模收敛慢”两个老毛病——不是改了蚁群本身,而是改了它脚下的搜索空间。

5. 避坑与排查:这套组合拳最容易翻车的几个地方

5.1 聚类簇数 K 拍脑袋定,分区数跟着失控

现象:K 设大了,障碍物被切成很多小簇,SVM 分割面数量上升,最终分区数不降反升,蚁群效率没改善。原因:K-Means 的 K 直接决定簇结构,而分区数由簇间间隔面数量派生,两者是链式关系。解决:先按障碍物团块数量估一个 K 上限,跑一次横向聚类看簇心在 x 轴上的分布,簇心挤在一起就说明 K 偏大,合并后再进 SVM。

5.2 距离度量用错,SVM 找不到干净的分割面

现象:用全欧几里得距离聚类后,SVM 分类面歪斜,多边形边界穿过障碍物密集区,分区后区域内仍有大量不可通行栅格。原因:团块状聚类让类间重叠严重,线性可分假设不成立。解决:分区目标决定度量方式,要纵向切图就用横坐标距离,让簇在切分方向上拉开;如果地图本身是横向长条,就换成纵坐标距离。

5.3 空簇导致簇心更新除零

现象:迭代中途报除零或 NaN,簇心坐标变成 inf。原因:某个初始簇心附近没有障碍物点,labels == k为空,均值计算出错。解决:初始化时用 k-means++ 式的远点采样代替纯随机,或在更新时保留上一轮簇心作为空簇兜底,代码里那行if np.any(...)就是干这个的。

5.4 多边形边界与栅格整数坐标重合

现象:分区结果里某些栅格归属随机跳变,同一行出现不连续分区编号。原因:边界 x 正好等于整数,x + 0.5的比较在边界两侧不稳定。解决:统一用栅格中点比较,边界值加一个极小偏移,或者把边界 x 排序后做左闭右开区间划分。

5.5 蚁群参数照搬未分区场景

现象:分区后仍然 50 代不收敛,或者早期就锁死在一条次优路径。原因:分区缩小了搜索空间,原参数下信息素累积速度相对变快,ρ 和 β 的平衡被打破。解决:分区后适当调大 ρ 加快挥发、防止过早聚焦,或降低 β 让探索比例回升,参数要跟着搜索空间规模重新标定。

6. 设计取舍:为什么“先降复杂度再搜索”比“改搜索算法”更划算

这套方法最值得琢磨的地方,是它没有去改蚁群算法的转移规则或信息素模型,而是把力气花在搜索空间的前处理上。这是一个典型的分层设计取舍:蚁群算法的收敛速度对问题规模高度敏感,与其在算法内部加各种改进策略,不如先把图缩小、把无效结构屏蔽掉。K-Means 负责“压缩障碍物表示”,SVM 负责“找全局切分面”,两者各干一件几何上定义清晰的事,组合起来就把分区数压到比四叉树和 Boustrophedon 更低的水平。

但取舍也有代价。SVM 的线性可分假设在障碍物分布极度不规则时会失效,这时要么换核函数,要么退回单元分解;K-Means 的 K 需要人工先验,自适应选 K 是这套流程里最脆弱的一环。我一般会这么理解:这套组合适合“障碍物成团、地图尺度中等、追求分区数少”的清洁机器人全局规划场景,不适合障碍物均匀散布或地图频繁动态变化的场合。

验证这套机制是否真的 work,最直接的办法是固定蚁群参数,只对比分区前后的收敛曲线和首次达到最优路径的迭代代数;再固定分区结果,换不同 K 看分区数与收敛代数的关系曲线,拐点就是合理 K 区间。源码和仿真脚本里这些对比实验都有对应入口,拿到资源后建议先把 K 和距离度量两个变量单独拉出来跑一遍,比通读全文更能建立直觉。从那以后我每次碰分区类路径规划,都强制先把“分区数—收敛代数”曲线画出来再调蚁群参数,不然很容易在错误的分区粒度上白调半天。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进