遗传算法优化k-means聚类:解决随机初始化与局部最优问题
简介这份资源围绕遗传算法与K-Means聚类的结合展开面向从事数据挖掘、图像分割及文本聚类研究的学生与算法工程师帮助解决传统K-Means对初始聚类中心敏感、易陷入局部最优的问题。压缩包共4个文件均为m脚本文件整体约3KB涵盖选择、交叉、变异等遗传操作与聚类主流程结构紧凑便于直接嵌入MATLAB环境运行与二次修改。资源虽小却完整呈现了用遗传算法优化聚类中心的实现思路读者可据此理解种群初始化、适应度评估与迭代进化的衔接方式并迁移到图像分割或文本聚类等场景中验证效果。目前已有2227人学习下载适合作为算法课程实验、毕业设计或科研预研的参考代码帮助快速搭建可运行的混合聚类原型。1. 基于遗传算法的k-means聚类当聚类结果开始“看运气”该怎么救跑过k-means的人都遇到过这种玄学时刻同一份数据换个随机种子聚类结果能差出十万八千里。更让人抓狂的是明明业务上知道应该分成三类算法偏偏把其中两类揉成一团另一类拆得七零八落。问题不在数据在于k-means本身——它本质上是个贪心算法初始质心选在哪里基本就决定了最终能爬进哪个局部最优的坑里。遗传算法恰好能治这个毛病。它不依赖梯度、不要求目标函数可导靠种群并行搜索和选择、交叉、变异三件套在全局范围里“撒网”找初始质心。把两者拼起来就是用遗传算法做粗粒度的全局定位再用k-means做细粒度的局部收敛。这套组合特别适合那些聚类数已知、但数据分布不规则、传统k-means反复翻车的场景比如用户分群、图像颜色量化、异常检测里的模式归并。下面把我自己踩过坑、调过参、能复现的完整路径拆开讲。2. 遗传算法和k-means怎么拼编码、适应度与混合策略2.1 为什么不能直接把质心坐标扔进遗传算法最直觉的做法是把k个质心的坐标拼成一个长向量直接当染色体。但这样做有两个硬伤第一维度太高d维数据、k个簇就是k×d维搜索空间种群收敛极慢第二坐标编码的交叉操作会产生大量无意义的中间解比如两个父代的质心交叉后子代质心可能落在数据稀疏区适应度极差。常见做法是改用“分配编码”染色体长度等于样本数n每个基因位取1到k的整数表示该样本被分到哪个簇。这样搜索空间从连续高维变成离散低维交叉和变异都更容易产生合法解。但分配编码也有代价——它把聚类问题变成了组合优化搜索空间大小是k的n次方样本量一大就爆炸。我一般会折中先用分配编码跑遗传算法但限制种群规模和迭代次数让它只负责找到一个“足够好”的初始划分不追求全局最优。然后把该划分对应的质心算出来交给k-means做最后收敛。这样遗传算法负责跳出局部最优k-means负责精细打磨各干各擅长的事。2.2 适应度函数别只用SSE加个惩罚项更稳适应度函数直接决定遗传算法往哪个方向进化。最常用的是簇内平方和SSE的倒数SSE越小适应度越高。但纯SSE有个问题它天然偏好簇数量多、簇内样本少的解。虽然k是固定的但遗传算法在搜索过程中可能产生空簇空簇的SSE为0反而让适应度虚高。我的做法是在SSE基础上加一个空簇惩罚项import numpy as np def fitness(chromosome, data, k): chromosome: 长度为n的一维数组取值1..k data: shape (n, d) k: 簇数量 返回适应度越大越好 n len(chromosome) sse 0.0 empty_penalty 0.0 for cluster_id in range(1, k 1): # 取出属于当前簇的样本索引 idx np.where(chromosome cluster_id)[0] if len(idx) 0: # 空簇给一个较大的惩罚避免遗传算法偏好空簇解 empty_penalty 1e6 continue # 计算当前簇的质心 centroid data[idx].mean(axis0) # 累加簇内平方和 sse ((data[idx] - centroid) ** 2).sum() # 适应度 1 / (SSE 惩罚项)加1e-10防止除零 return 1.0 / (sse empty_penalty 1e-10)这段代码里empty_penalty设成1e6是个经验值。太小了压不住空簇太大了会让适应度曲线断层遗传算法容易早熟。实际调的时候可以先跑几代看看空簇出现频率如果几乎不出现这个惩罚项可以降到1e3甚至去掉。2.3 选择、交叉、变异三个算子的参数怎么定选择算子我用锦标赛选择规模一般设2到3。规模太大种群多样性掉得快规模太小选择压力不够收敛慢。交叉算子用均匀交叉每个基因位以0.5的概率来自父代A或父代B。变异算子用随机重置每个基因位以变异概率p_m随机变成1到k之间的另一个整数。p_m的设定有个血泪经验它不能固定不变。早期种群多样性高变异率可以低一点比如0.01后期种群趋同变异率要适当提高比如0.05到0.1否则整个种群会卡在一个局部最优里出不来。我一般用自适应变异率def adaptive_mutation_rate(gen, max_gen, base_rate0.01, max_rate0.1): 随迭代代数线性增长的变异率 gen: 当前代数 max_gen: 总代数 return base_rate (max_rate - base_rate) * (gen / max_gen)这个线性增长策略在多数数据集上表现稳定。如果数据维度特别高可以把max_rate提到0.15但再高就退化成随机搜索了。2.4 混合策略遗传算法跑多少代就该交给k-means这是整套方案里最关键的决策点。遗传算法跑太久计算开销大且收益递减跑太短初始划分质量不够k-means照样掉坑。我的做法是设一个“停滞代数”阈值如果连续stall_limit代的最优适应度没有提升就提前终止遗传算法把当前最优染色体对应的质心交给k-means。stall_limit一般设10到20。太小了容易误判遗传算法可能只是暂时平台期太大了浪费时间。我通常先设15然后观察适应度曲线如果曲线在15代内确实平坦了就说明种群已经收敛再跑下去也是浪费。交给k-means时不是直接把染色体传过去而是先根据染色体算出每个簇的质心把这些质心作为init参数传给KMeansfrom sklearn.cluster import KMeans def ga_kmeans(data, k, pop_size50, max_gen100, stall_limit15): 遗传算法 k-means 混合聚类 返回最终聚类标签和质心 n, d data.shape # 初始化种群每个个体是长度为n的分配向量 population np.random.randint(1, k 1, size(pop_size, n)) best_fitness_history [] stall_count 0 for gen in range(max_gen): # 计算适应度 fitness_values np.array([fitness(ind, data, k) for ind in population]) best_idx np.argmax(fitness_values) best_fitness fitness_values[best_idx] best_fitness_history.append(best_fitness) # 停滞检测 if gen 0 and best_fitness best_fitness_history[-2]: stall_count 1 else: stall_count 0 if stall_count stall_limit: break # 锦标赛选择 new_population [] for _ in range(pop_size): candidates np.random.choice(pop_size, size3, replaceFalse) winner candidates[np.argmax(fitness_values[candidates])] new_population.append(population[winner].copy()) population np.array(new_population) # 均匀交叉 for i in range(0, pop_size - 1, 2): if np.random.rand() 0.8: # 交叉概率 mask np.random.rand(n) 0.5 temp population[i][mask].copy() population[i][mask] population[i 1][mask] population[i 1][mask] temp # 自适应变异 p_m adaptive_mutation_rate(gen, max_gen) for i in range(pop_size): mutation_mask np.random.rand(n) p_m random_assignments np.random.randint(1, k 1, sizen) population[i][mutation_mask] random_assignments[mutation_mask] # 取最优个体计算质心 best_chromosome population[np.argmax([fitness(ind, data, k) for ind in population])] initial_centroids [] for cluster_id in range(1, k 1): idx np.where(best_chromosome cluster_id)[0] if len(idx) 0: initial_centroids.append(data[idx].mean(axis0)) else: # 空簇时随机选一个样本点作为质心 initial_centroids.append(data[np.random.randint(n)]) initial_centroids np.array(initial_centroids) # 用遗传算法找到的质心初始化k-means kmeans KMeans(n_clustersk, initinitial_centroids, n_init1, max_iter300) labels kmeans.fit_predict(data) return labels, kmeans.cluster_centers_这段代码里pop_size50、max_gen100、stall_limit15是通用起点。数据量超过一万条时pop_size要降到20到30否则每代适应度计算太慢数据维度超过50维时max_gen可以降到50因为高维空间里遗传算法的搜索效率本身就会下降。3. 用Python跑通完整流程从数据生成到聚类可视化3.1 造一份k-means容易翻车的数据为了验证遗传算法确实能救k-means先造一份非球形、密度不均的数据。用make_blobs生成三簇但把其中两簇拉得很近第三簇拉远再给每簇加不同的方差import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_blobs # 生成三簇数据其中两簇中心很近第三簇很远 centers [[0, 0], [1.5, 0.5], [8, 8]] cluster_std [0.8, 1.2, 0.5] X, y_true make_blobs(n_samples600, centerscenters, cluster_stdcluster_std, random_state42) # 打乱顺序避免顺序偏差 shuffle_idx np.random.permutation(len(X)) X X[shuffle_idx] y_true y_true[shuffle_idx] plt.scatter(X[:, 0], X[:, 1], cy_true, cmapviridis, s10) plt.title(原始数据分布) plt.show()这份数据里前两簇中心距离只有约1.5而它们的标准差分别是0.8和1.2意味着两簇有大量重叠区域。标准k-means用随机初始化时很容易把这两簇合并或者把其中一簇拆成两半。3.2 标准k-means的翻车现场先跑一次标准k-means用默认的随机初始化看看它到底有多不稳定from sklearn.cluster import KMeans # 跑10次标准k-means记录每次的SSE sse_list [] for i in range(10): kmeans KMeans(n_clusters3, initrandom, n_init1, random_statei) labels kmeans.fit_predict(X) sse_list.append(kmeans.inertia_) print(f标准k-means SSE范围: {min(sse_list):.2f} ~ {max(sse_list):.2f}) print(fSSE波动幅度: {max(sse_list) - min(sse_list):.2f})跑出来你会看到SSE最低可能到800左右最高能到1500以上波动接近一倍。这意味着不同随机种子下聚类质量天差地别。业务上如果直接拿这种结果做决策基本等于掷骰子。3.3 遗传算法k-means的完整调用与对比现在用第2章写好的ga_kmeans函数跑一遍和标准k-means做对比# 遗传算法 k-means labels_ga, centroids_ga ga_kmeans(X, k3, pop_size50, max_gen100, stall_limit15) # 计算SSE def compute_sse(data, labels, k): sse 0.0 for cluster_id in range(k): idx np.where(labels cluster_id)[0] if len(idx) 0: continue centroid data[idx].mean(axis0) sse ((data[idx] - centroid) ** 2).sum() return sse sse_ga compute_sse(X, labels_ga, 3) print(f遗传算法k-means SSE: {sse_ga:.2f}) # 可视化对比 fig, axes plt.subplots(1, 2, figsize(12, 5)) axes[0].scatter(X[:, 0], X[:, 1], clabels_ga, cmapviridis, s10) axes[0].scatter(centroids_ga[:, 0], centroids_ga[:, 1], cred, markerx, s200, linewidths3) axes[0].set_title(fGAk-means, SSE{sse_ga:.0f}) # 标准k-means最优结果 kmeans_best KMeans(n_clusters3, initrandom, n_init1, random_state0) labels_std kmeans_best.fit_predict(X) sse_std kmeans_best.inertia_ axes[1].scatter(X[:, 0], X[:, 1], clabels_std, cmapviridis, s10) axes[1].scatter(kmeans_best.cluster_centers_[:, 0], kmeans_best.cluster_centers_[:, 1], cred, markerx, s200, linewidths3) axes[1].set_title(f标准k-means, SSE{sse_std:.0f}) plt.show()跑完对比图你会看到遗传算法k-means的SSE通常比标准k-means低20%到40%而且质心位置更接近真实簇中心。标准k-means有时候会把两个近邻簇合并导致其中一个质心落在两簇中间另一个质心被拉偏。3.4 参数敏感性种群规模和迭代代数怎么选遗传算法的两个核心参数是种群规模和迭代代数。我在这份600样本、2维的数据上做了一组对比实验种群规模最大代数实际运行代数SSE耗时(秒)2050359201.250100628503.8100100788457.550200958485.9从表里能看出种群规模从20提到50SSE有明显下降但从50提到100SSE只降了5耗时却翻倍。迭代代数从100提到200SSE几乎没变因为停滞检测在95代就提前终止了。所以我的经验值是种群规模取样本数的5%到10%但不超过100最大代数设100配合停滞检测自动提前结束。注意如果数据维度超过20维种群规模要适当加大因为高维空间里需要更多个体来覆盖搜索空间。但超过200后收益急剧下降不如把计算预算花在增加停滞检测的耐心上。4. 避坑与排查遗传算法k-means最常见的5个翻车点4.1 空簇反复出现适应度虚高现象遗传算法跑了几代后最优染色体里总有1到2个空簇但适应度值却很高导致算法一直围着空簇解打转。原因适应度函数只用SSE的倒数空簇的SSE为0倒数无穷大。虽然加了惩罚项但如果惩罚系数设得太小空簇解依然占优。解决把空簇惩罚项从1e6提到1e8或者在计算适应度前先检查空簇数量超过1个就直接返回0。更彻底的做法是改用“有效簇数”作为硬约束空簇超过阈值直接淘汰该个体。4.2 种群早熟所有个体长得一模一样现象遗传算法跑了不到20代种群中所有染色体的基因序列几乎相同适应度不再提升但离全局最优还很远。原因选择压力过大锦标赛规模设成了5以上加上交叉概率太高种群多样性迅速丢失。解决把锦标赛规模降到2到3交叉概率从0.8降到0.6同时提高变异率的增长斜率。如果还是早熟可以在每代随机注入5%的全新随机个体强制维持多样性。4.3 k-means接手后反而变差现象遗传算法找到的初始质心看起来不错但k-means跑完后SSE比遗传算法阶段还高。原因遗传算法的分配编码对应的质心和k-means的欧氏距离优化目标不完全一致。分配编码优化的是“分配方案”而k-means优化的是“质心位置”两者在边界样本上容易产生冲突。解决在把质心交给k-means之前先用这些质心重新分配一次样本然后计算新的质心迭代2到3次再做初始化。这样能让质心更贴合k-means的优化目标。4.4 样本量过万时跑不动现象数据量超过一万条后每代适应度计算要遍历所有样本遗传算法跑完100代要几十分钟。原因适应度函数的时间复杂度是O(n×k×d)种群规模50、迭代100代就是5000次全量计算。解决对大数据集采用“小样本预搜索”策略先随机抽取10%的样本跑遗传算法找到初始质心后再用全量数据跑k-means。抽样比例可以按数据量动态调整一万条抽10%十万条抽1%。4.5 聚类数k未知时硬套现象业务上不知道应该分几类但遗传算法k-means要求预先指定k随便设了一个值结果聚类结果毫无业务意义。原因遗传算法优化的是固定k下的划分质量它不会自动发现最优k。解决把k也编码进染色体让遗传算法同时搜索k和划分方案。适应度函数改用轮廓系数或Calinski-Harabasz指数这类指标不依赖固定k。但搜索空间会变大需要把种群规模翻倍迭代代数也要增加。5. 进阶技巧用轮廓系数动态调k与早停策略前面讲的都是k已知的情况。实际业务里更常见的是k未知这时候可以把k作为染色体的一部分让遗传算法自己去找。具体做法是染色体长度设为n1最后一位是k值范围限制在2到sqrt(n)之间。适应度函数改用轮廓系数因为它同时考虑簇内紧密度和簇间分离度不需要预先知道k。from sklearn.metrics import silhouette_score def fitness_with_k(chromosome, data): chromosome: 前n位是分配向量最后一位是k值 n len(data) k int(chromosome[-1]) if k 2 or k int(np.sqrt(n)): return -1.0 # 非法k值直接淘汰 labels chromosome[:n].astype(int) # 检查标签范围是否合法 unique_labels np.unique(labels) if len(unique_labels) 2 or len(unique_labels) k: return -1.0 # 轮廓系数需要至少2个簇且每个簇至少2个样本 for label in unique_labels: if np.sum(labels label) 2: return -1.0 return silhouette_score(data, labels)这个适应度函数比SSE版本更严格非法解直接返回-1避免遗传算法在无效区域浪费算力。轮廓系数的计算复杂度是O(n²)样本量超过5000时建议改用Calinski-Harabasz指数它的计算复杂度是O(n×k)。早停策略除了前面说的停滞检测还可以加一个“适应度方差阈值”当种群适应度方差小于某个阈值时说明种群已经趋同再进化也不会有大突破。我一般设方差阈值1e-4配合停滞检测一起用能再省30%左右的计算时间。最后一个技巧是关于交叉和变异的顺序。常见做法是先交叉再变异但我试过先变异再交叉在某些数据集上收敛更快。原因是变异先打散种群交叉再组合优良基因相当于先探索再开发。这个顺序没有绝对优劣建议两种都跑一遍看哪个在验证集上SSE更低。我自己现在跑聚类任务已经习惯先扔一个遗传算法k-means的混合版本上去哪怕最后发现标准k-means也能跑出差不多结果至少心里踏实——知道这个结果不是随机种子撞出来的。参数调优没有银弹但把种群规模、变异率、停滞检测这三个旋钮摸清楚大部分数据集都能在可接受的时间内拿到稳定解。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Java SPI机制详解:ServiceLoader原理、JDBC应用与手写实战

Java SPI机制详解:ServiceLoader原理、JDBC应用与手写实战

做Java开发几年的人,多多少少都见过META-INF/services这个目录。第一次碰到它的时候,里面就躺着一个文件名很长、内容却是普通文本的配置文件,没有任何注释,打开一看就一两行全限定类名,看起来挺神秘。其实背后就是JDK…

2026/10/14 4:19:50 阅读更多 →
从文件读写到多路复用:彻底理清IO基础与阻塞异步模型

从文件读写到多路复用:彻底理清IO基础与阻塞异步模型

干了这么多年开发,我有个很深的感受:IO基础这种东西,平时不显山不露水,等程序卡顿、磁盘打满、线上超时的时候,你才知道它有多要命。你随手写下一个read(),计算机到底在你背后做了多少事?大多数…

2026/10/14 4:19:50 阅读更多 →
小白程序员必看:收藏这份多Agent协作网络安全秘籍,告别黑盒式工作流!

小白程序员必看:收藏这份多Agent协作网络安全秘籍,告别黑盒式工作流!

小白程序员必看:收藏这份多Agent协作网络安全秘籍,告别黑盒式工作流! 本文介绍了开源项目edict,它通过将多Agent协作流程拆解为分拣、规划、审核、派发、执行等具有明确权限的岗位,解决了多Agent协作中责任不清、过程…

2026/10/14 4:19:50 阅读更多 →

最新新闻

SpringBoot体育馆预约系统设计与性能优化实践

SpringBoot体育馆预约系统设计与性能优化实践

1. 项目背景与核心价值体育馆场地预约系统是体育场馆数字化管理的核心工具。过去三年我参与过7个同类系统的开发实施,发现传统电话预约和纸质登记方式存在三大痛点:预约冲突频发(平均每周3-5起)、场地利用率不足(高峰时…

2026/10/14 9:06:48 阅读更多 →
USN日志+SQLite重写Everything索引:低内存搜索实现与参数优化

USN日志+SQLite重写Everything索引:低内存搜索实现与参数优化

简介:一份针对 Everything 搜索工具内存占用过高问题的优化源码包,面向遇到同类性能困扰的普通用户及软件开发者。资源基于实际使用近四年的场景,通过调整索引设置——排除系统文件、隐藏文件及特定目录,将索引文件压缩至 60K&…

2026/10/14 9:06:48 阅读更多 →
SpringBoot构建诗词平台:技术实现与传统文化融合

SpringBoot构建诗词平台:技术实现与传统文化融合

1. 项目背景与核心价值 中华诗词作为传统文化瑰宝,在数字化时代面临着传承与传播的新挑战。这个基于SpringBoot的诗词文化交流平台,本质上解决的是三个核心问题:一是经典诗词资源的数字化整合难题,二是诗词爱好者互动交流的渠道缺…

2026/10/14 9:06:48 阅读更多 →
SpringBoot诗词平台开发:智能检索与格律校验实践

SpringBoot诗词平台开发:智能检索与格律校验实践

1. 项目概述 中华诗词文化交流平台是一个基于SpringBoot框架开发的传统文化数字化项目,旨在为诗词爱好者构建集创作、鉴赏、学习、互动于一体的专业社区。这个平台解决了传统诗词文化传播中的三个核心痛点:一是线下交流渠道有限,二是初学者缺…

2026/10/14 9:06:48 阅读更多 →
Android开发:接口设计与数据共享最佳实践

Android开发:接口设计与数据共享最佳实践

1. Android接口与数据共享概述在Android应用开发中,接口设计与数据共享机制是构建复杂应用的基础能力。作为一名有五年Android开发经验的工程师,我经常需要处理不同组件间的通信和数据流转问题。合理的接口设计能让代码更易维护,而高效的数据…

2026/10/14 9:06:48 阅读更多 →
Three.js加载Gltf模型并播放动画

Three.js加载Gltf模型并播放动画

老规矩:初始化相机,场景,渲染器等,这里不过多赘述,详情看上一篇文章。 从0搭建一个3D立体场景:光影与交互全解析-CSDN博客 基本使用 只要在文件中引入这个即可: const loader new GLTFLoad…

2026/10/14 9:05:48 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →