吉布斯采样实现LDA主题模型:MATLAB代码实战与避坑指南
简介面向机器学习和自然语言处理方向开发者的开源实现基于吉布斯采样方法完成LDA主题模型推断帮助解决高维概率分布采样的核心难题适用于文本挖掘、主题建模等场景也适合作为MCMC算法入门的代码范本。资源共15个文件以5个h头文件和4个cpp源文件为主涵盖constants、dataset、model、strtokenizer等核心模块另有Makefile、CMakeLists构建脚本、README说明及PDF手册、HTML文档等辅助材料完整呈现了从数据预处理到采样迭代、结果输出的工程链路整体仅55KB结构清晰轻量。已有604人学习/下载。通过研究这份代码可以理解吉布斯采样的迭代更新逻辑、主题分布和词分布的推断方式掌握文本数据的分词、停用词过滤和词汇表构建流程为后续在NLP任务中扩展优化主题模型打下基础同时也为参与开源项目协作提供参考。1. 吉布斯采样matlab代码GibbsLDA帮我跑通了课程设计里的主题模型接到课程设计要复现一篇中文论文里的LDA主题模型时我第一时间想到的不是调现成包而是找一套能跑、能改、能打印中间状态的代码。这套GibbsLDA的matlab版本就是我当时找到的那个突破口代码量不大一个系统开源项目核心逻辑全摊开用吉布斯采样把“文档—主题—词”的后验分布一步步抽出来。它解决的是从“知道原理”到“亲手跑出结果”之间的落差适合正在做文本挖掘课设、想验证LDA算法实现细节或者需要把主题模型嵌入自己预处理流程的工程师。和其他语言版本比MATLAB版本的优势在于矩阵操作直观调试时直接看变量采样循环每一步都能停下来问“你现在凭什么给这个词分配主题”。2. 核心原理吉布斯采样如何从文本中抽出主题2.1 LDA的生成过程与两个需要估的随机变量LDA不是直接算主题而是假设每篇文档是若干主题的混合每个词由某个主题生成。你观察到的只有文档里的词主题分配是隐藏变量。吉布斯采样的思路是先把所有词随机扔到K个主题里然后逐个词地重新抽主题抽的时候固定其他所有词的主题分配按条件概率来选。条件概率的形状是% 伪代码词w被分到主题k的条件概率 % p(k | w, 其他词的主题) ∝ % (n_dk alpha_k) / (sum_k n_dk K * alpha) * % (n_kw beta_w) / (sum_w n_kw V * beta)第一项是“文档d已经有多少词属于主题k”代表该文档对主题k的偏好第二项是“整个语料里主题k给了词w多少次”代表这个词与主题k的绑定强度。两者相乘正常化之后就是重新采样该词主题的分布。某开发者在这份代码里把这两项直接写成了两个矩阵的逐元素相乘效率不错但前提是你得先维护好计数矩阵。这套代码卷一进来就能看到几个核心文件主函数、初始化文件、采样引擎和结果输出。文件名我记不太准可能是gibbs_lda_main.m、init_model.m、sample_lda.m这种风格但逻辑基本一致。主函数负责读取参数、调用预处理好的词计数矩阵初始化负责分配首轮随机主题并建立两个关键计数——文档-主题计数矩阵和主题-词计数矩阵采样引擎才是真正的灵魂它按“文档-词”的顺序遍历整个语料每遍历一个词就重新抽一次主题然后立刻更新计数矩阵。2.2 采样循环从随机状态到稳态的每一步我一般喜欢把采样循环单独看它也是最容易改出问题的地方。常见的实现长这样% sampling_engine.m 核心循环示意 for iter 1 : total_iterations for d 1 : D for n 1 : Nd(d) w doc_words{d}(n); % 当前词 k_old z{d}(n); % 旧主题 % 先从计数矩阵中减去当前词的对主导贡献 n_dk(d, k_old) n_dk(d, k_old) - 1; n_kw(k_old, w) n_kw(k_old, w) - 1; % 计算每个主题的条件概率 p (n_dk(d,:) alpha) .* (n_kw(:,w) beta) ; p p / sum(p); % 按p重新采样主题 k_new randsample(K, 1, true, p); z{d}(n) k_new; n_dk(d, k_new) n_dk(d, k_new) 1; n_kw(k_new, w) n_kw(k_new, w) 1; end end % 每若干次迭代记录对数似然或困惑度 end注意上面的循环实现里我先“减”后“加”保证采样当前词时它自己不计入计数。这是吉布斯采样正确性的关键如果忘了减模型会趋向把所有词都堆到同一个主题上。这段代码里有两个地方容易写错一个是sum(p)归一化前要先保证p是行向量还是列向量另一个是randsample函数的权重必须非负归一化否则MATLAB会报“概率必须为正”的错误。我在实际调试时就把这两个错误都犯过后面避坑章节再细说。3. 把代码跑起来数据准备、参数设置与第一次采样3.1 文档格式和预处理先造出适合GibbsLDA的输入这份MATLAB代码接收的不是原始txt而是已经转换成数字ID的“词索引序列”。常见输入格式有两种一种是D行V列的稀疏计数矩阵matrix(d, w) 文档d中词w出现的次数另一种是cell数组doc_words{d}里存的是文档d的词ID向量每个元素是词表里的索引。系统开源包里默认走的是cell数组因为这种格式更容易在采样时逐个词遍历也方便保留词的先后信息。我自己在跑的时候首先得把原始语料切成词去掉标点、转小写、去停用词然后建立“词串-ID”的映射。下面是一段我常用的MATLAB预处理脚本可以直接替换掉示例里的loader% preprocess_corpus.m % 把原始文本cell数组转为词ID向量cell数组 function [docs, vocab] preprocess_corpus(raw_cells, min_freq) % raw_cells: 1 x D 的cell每个cell存放一篇文章字符串 % min_freq: 低频词过滤阈值低于该值的词删除 all_words containers.Map(KeyType,char,ValueType,double); word_id_map containers.Map(KeyType,char,ValueType,int32); docs cell(size(raw_cells)); % 第一遍统计词频 for d 1 : length(raw_cells) tokens strsplit(lower(raw_cells{d}), { , ,, ., 。, }); for t 1 : length(tokens) if isempty(tokens{t}) || length(tokens{t}) 2 continue; end if isKey(all_words, tokens{t}) all_words(tokens{t}) all_words(tokens{t}) 1; else all_words(tokens{t}) 1; end end end % 第二遍给词分配ID过滤低频词 word_id 1; for d 1 : length(raw_cells) tokens strsplit(lower(raw_cells{d}), { , ,, ., 。, }); ids []; for t 1 : length(tokens) token tokens{t}; if isempty(token) || length(token) 2, continue; end if all_words(token) min_freq, continue; end if ~isKey(word_id_map, token) word_id_map(token) word_id; word_id word_id 1; end ids(end1) word_id_map(token); %#okAGROW end docs{d} ids; end vocab keys(word_id_map); end这段脚本的逻辑是两遍扫描第一遍统计全语料每词出现次数第二遍决定哪些词进入词表。min_freq我习惯设成5既可以去掉打错产生的噪声又不至于把真实内容剪得太狠。length(tokens) 2的过滤是避免单字符数字、语气词进入采样因为这个工具包没有内置去停用词表它假设你已经把该清的词清掉了。有一个小坑这段代码用strsplit按固定分隔符切中文语料如果里面还有顿号、分号都得加进分隔符列表不然词串会被连在一起导致词表爆炸。3.2 主题数、超参数和迭代次数这些数字不是玄学跑GibbsLDA之前最常被问的三个问题主题数K怎么选alpha和beta设多少迭代多少次算够。这套代码里参数都集中在主函数头部我习惯用表格列出并说明影响参数常见默认值建议范围改了会怎样K 主题数105~100K太小主题混在一起K太大主题碎成词堆alpha 文档-主题超参150/K 比较常用越大每篇文档主题分布越平滑越小越容易只聚焦一个主题beta 主题-词超参0.010.001~0.1越大主题词分布越平滑越小主题词越尖锐iterations 采样总轮数500200~5000太少未收敛太多浪费时间burn-in 丢弃轮数100iterations的1/5到1/2用于去掉初始随机状态的影响关于alpha某篇经典教程里提到过一个经验值alpha 50 / K因为这样sum(alpha) 50等于给每篇文档一个整体狄利克雷先验强度。我实际用下来K在20以内这个值比较稳K超过50时会偏保守这时我会把alpha调回0.5上下。beta则主要看词表大小词表越大beta应该越小否则主题-词分布过于均匀top词不带区分度。选好参数后运行主函数的方法非常简单% run_gibbs_lda.m % 假设docs是预处理好的cell数组vocab是词名cell数组 K 10; alpha 5; % 等于 50/KK10时取5 beta 0.01; iterations 500; burn_in 100; % 调用GibbsLDA主函数返回theta、phi和词主题分配z [theta, phi, z, loglik] gibbs_lda(docs, vocab, K, alpha, beta, iterations, burn_in); % theta是D x K的文档-主题分布每行和为1 % phi是K x V的主题-词分布每行和为1这里loglik是每次采样迭代算出的对数似然主要用来判断模型有没有收敛而不是模型质量。很多初学者以为loglik越大模型越好其实只代表“训练集上拟合程度高”不代表主题有多合理。真正要看的是后续主题一致性检验。函数内部输出结果时一般会把phi保存为主题-词矩阵每行按词频降序排序后取前十就是最常见的主题词列表。3.3 第一次运行后看什么中间状态怎么检查不要一跑完就直接看主题词。建议第一次运行时把采样循环里的loglik画出来观察它是否在开头几十轮快速上升然后逐渐平缓。如果画出来是锯齿状一路下降说明数据格式有严重问题。常见检查点有两个文档平均长度不能所有文档都只有一两个词词表大小如果被过滤到只剩几十个词主题估计一定不准。% 检查loglik曲线是否收敛 figure; plot(loglik); xlabel(迭代轮数); ylabel(对数似然); title(Gibbs采样收敛诊断);如果曲线在burn-in之后还在大幅摆动说明K太大或者alpha太小。这时不要盲目加迭代次数先把K调小试一轮再看曲线形状。另外phi矩阵的行可以打印前五行看高频词如果每行都是“的”“是”“在”这类停用词说明预处理阶段没清干净返回去重跑。4. 避坑与常见问题五条吉布斯采样现场排错记录4.1 现象运行直接报错“Index exceeds array bounds.”检查了半天不知道是哪个变量越界原因MATLAB数组索引从1开始而很多开源文本处理工具习惯用0作为词ID起点。我现在这份语料来自某公司的公开搜索日志词表工具输出的是0基ID直接喂给GibbsLDA所有n_kw(:,w)都会在w0处崩掉。解决在预处理脚本里强制把词ID从1开始编号并加一个断言assert(min(min(doc_word_ids)) 1, 文档词索引必须从1开始);从那以后我每次跑这套代码都会在给词表编号时先打印最小ID和最大ID确认再进入采样。只要记住MATLAB的世界里没有0号词这一类的坑就断根了。4.2 现象所有主题都长一样前几个主题的高频词全是“的、是、在、和、了”原因不是GibbsLDA实现错了而是语料预处理阶段没把高频功能词滤掉。吉布斯采样会优先把高频词分给任意主题因为这些词在每篇文档里都出现确证的证据太强导致每个主题的“大众词”权重都很大真正的主题词被淹没在后面。解决在构造词表前先跑一遍停用词过滤。我有一个习惯把全语料按词频排序直接盯住前100个词凡是与主题无关的虚词、标点、无意义数字全部用手动停用词表过滤。注意工具包自带的停用词表只能去掉一部分中文的“例如”、“其中”、“相关”这类学术高频词也需要自己补。补充后重新统计词频直到每个主题的前十个词里不再出现明显与主题无关的词。4.3 现象连续跑三次同样的数据主题结果每次都不一样甚至主题名称都换了风格原因吉布斯采样本身依赖随机数而这套MATLAB代码在初始化时用了随机生成器却没有固定随机种子。如果你在脚本里不设置rng状态MATLAB每次启动时默认随机状态不同最终采到的局部最优也不同。解决在主函数开头固定随机种子同时把种子设置为语料哈希值这样任何语料都能稳定复现% 用语料的词ID总和生成种子 rng(sum(sum(doc_word_matrix)) 2024);固定种子不只为了复现结果也方便你调试当某个参数改动后看到主题变化你不会误以为算法不稳定而是能确定变化确实由该参数引起。某开发者在原始代码注释里写了“如果有强迫症就固定rng”我当时还觉得多余踩坑之后才明白这是最高性价比的一行代码。4.4 现象语料从几千篇扩展到十万篇时内存直接爆掉采样一个epoch从几秒变成几分钟原因这份MATLAB代码为了可读性用了一个全量的z矩阵和n_dk、n_kw两个密集计数矩阵。文档量大时z是D行×最长文档长度的矩阵哪怕很多位置是0也占用内存n_dk则是D×K的密集矩阵当D很大时这是可怕的内存负担。解决在保证逻辑不变的前提下把全量矩阵改成稀疏存储。n_dk用稀疏矩阵sparse声明z不用矩阵而用cell数组每篇文档只存自己非零的序列。更重要的是采样时在处理某篇文档前先把计数更新合并成局部视图减小高频随机访问带来的开销。实际改完十万篇文档、K100的规模内存占用降到原来的三分之一每轮采样时间缩短了约四成。如果你只需要跑一个小数据集密集版本没问题想上规模优先改这两个数据结构。4.5 现象burn-in设置为200总共跑1000轮loglik曲线已经平了但主题词的语义还是乱看了三行也总结不出主题原因这是典型的K取值过大。我拿300篇文档的主题语料去跑K设了50结果每个主题都被拆成碎片导致同一个真实主题被拆成十几个小主题。对数似然在“过拟合”下仍然会很高因为Gibbs采样有机会把每个词都分给专属主题来解释。解决先用一个更小的K比如K5跑通整个流程观察主题词能否概括为一个清晰的标签。如果5个主题下仍然乱问题多半出在语料预处理或词表质量而不是K。之后再用“主题一致性”或“困惑度”折衷曲线确定K而不是拍脑袋定一个大值。我一般会在脚本里写一个K循环从5跑到30每次跑固定迭代次数然后对比结果选出最稳的K。5. 验证模型困惑度计算与主题一致性检查5.1 留出数据算困惑度别只盯着训练集似然训练集上的对数似然单调增加不奇怪真正能判断模型泛化能力的是在测试集上算困惑度。做法是把文档按词流切成两半前一半训练GibbsLDA后一半用来计算困惑度。计算时目标词的后验概率要用训练好的phi和文档-主题混合分布来近似。% compute_perplexity.m % log_perplexity -mean(log p(w_test | theta_est, phi)) % 这里theta_est用训练集的文档主题计数归一化 function perp compute_perplexity(phi, theta, test_docs) log_lik 0; total_tokens 0; for d 1 : length(test_docs) theta_d theta(d,:) / sum(theta(d,:)); for n 1 : length(test_docs{d}) w test_docs{d}(n); p_w sum(phi(:, w) .* theta_d); log_lik log_lik - log(p_w 1e-12); total_tokens total_tokens 1; end end perp exp(log_lik / total_tokens); end困惑度越低说明模型在没见过的词上预测越准。注意phi(:, w)是V维列向量theta_d是K维行向量两者逐元素相乘前要确认方向一致。我踩过theta_d方向反了的坑算出来的负数对数似然直接变负值一度以为代码坏了。后来我习惯在乘积前打印维度size(phi(:,w))和size(theta_d)必须一个是K×1、一个是K×1才能逐元素匹配。5.2 主题一致性检查比困惑度更能看出主题像不像话困惑度只关心预测概率大小并不关心主题词是否语义连贯。我现在的做法是对每个主题取前10个词计算两两在原始文档中的共现频率。共现值高的主题说明这组词确实常在一起出现而不是被采样噪声凑到一起。这个检查比困惑度更贴近人对“主题”的直觉。% 主题词共现矩阵 top_words cell(K, 10); for k 1 : K [~, idx] sort(phi(k,:), descend); top_words{k} vocab(idx(1:10)); end % 再遍历原始文档统计每对top词是否在同一文档出现从那以后我每次跑GibbsLDA都强制走一遍验证流程固定随机种子算测试集困惑度再看top词共现分。花不了几分钟但能把“看起来能跑”和“真正可以交报告”之间的差距填平。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

MES系统如何打通车间现场:从黑盒到透明,制造执行的核心价值解析

MES系统如何打通车间现场:从黑盒到透明,制造执行的核心价值解析

1. 从车间现场的“黑匣子”说起:MES到底在解决什么问题先说一个我在制造业圈子里反复听到的抱怨:很多企业的老板和管理者,花大价钱上了ERP,觉得“系统都有了,管理应该没问题了”,结果到了车间一看&#xff…

2026/10/17 4:39:12 阅读更多 →
Linux最小化系统搭建Firefox与VNC远程桌面完整指南

Linux最小化系统搭建Firefox与VNC远程桌面完整指南

一台用最小化模式装好的 Linux,装完就是纯命令行环境,连图形界面都没有。但很多时候,你又确实需要在这台机器上跑出一个有界面的浏览器——用 Firefox 登录网页后台、远程给同事演示页面效果,或者把一台旧电脑改成专用网页终端。于…

2026/10/17 4:39:12 阅读更多 →
神经网络六十年:从感知机到深度学习的演进之路

神经网络六十年:从感知机到深度学习的演进之路

神经网络这门技术,说白了是“熬”出来的。从感知机到深度神经网络,名字听着像是直线升级,实际上中间经历了被主流抛弃、被同行嘲笑、被资金断供的至暗时刻,又靠着几代研究者不服输的执念和几次偶然的算力突破,才一步步…

2026/10/17 4:39:12 阅读更多 →

最新新闻

Claude Code模板实战:CLAUDE.md、自定义命令与hooks全解析

Claude Code模板实战:CLAUDE.md、自定义命令与hooks全解析

1. 先把这个标题拆明白看到“claude-code-templates”这个项目名,估计大部分人都能猜个大概:这是给Claude Code用的模板集合。但真正用过Claude Code的人会知道,模板这两个字背后藏的东西远比想象中多——它不是简单的几段提示词,…

2026/10/17 5:22:24 阅读更多 →
人形机器人爆款视频背后:数据链路与训练技术深度解析

人形机器人爆款视频背后:数据链路与训练技术深度解析

最近几天人形机器人圈子里有两件挺有反差感的事。一条某国内头部厂商发布的训练视频在社交平台跑到了430万播放,评论区从“走路怎么像喝多了”一路聊到“这玩意儿多久能进我家干活”;另一边,海外一家AI实验室的机器人项目负责人离任的消息也在…

2026/10/17 5:22:24 阅读更多 →
MuJoCo Python仿真入门:环境搭建、核心对象与闭环控制

MuJoCo Python仿真入门:环境搭建、核心对象与闭环控制

MuJoCo这名字,搞机器人仿真和强化学习的应该不陌生。但你真说要用Python去操纵它跑起来、把仿真环境跟自己的算法接上,很多新手第一次都会卡在“这到底怎么下手”这一步。官方文档其实写得不算差,但内容偏散,一会儿讲建模语言&…

2026/10/17 5:22:24 阅读更多 →
人脸解析从PyTorch到ONNX/TFLite/NCNN/RKNN全链路部署实战

人脸解析从PyTorch到ONNX/TFLite/NCNN/RKNN全链路部署实战

人脸解析这个方向,我从早期的dlib关键点一路做到现在的BiSeNet语义分割,踩过的坑比跑通的模型还多。face-parsing听起来像是学术圈的名词,但落到实际项目里,它解决的是一个非常具体的问题:给你一张人脸照片&#xff0c…

2026/10/17 5:22:24 阅读更多 →
PHP借贷源码本地部署与二次开发实战:从环境配置到核心链路拆解

PHP借贷源码本地部署与二次开发实战:从环境配置到核心链路拆解

简介:这是一套基于PHP开发的借贷公司整站源码,面向需要快速搭建网贷平台或二次开发借贷系统的开发者与运维人员。源码由得得系统改编而来,经实际测试可正常运行,覆盖用户注册、信用评估、借款申请、还款计划、逾期处理等核心借贷流…

2026/10/17 5:22:24 阅读更多 →
Oh My Zsh主题配置全攻略:选型、定制与排错

Oh My Zsh主题配置全攻略:选型、定制与排错

1. 为什么我在折腾了十几个主题之后,还是回到了Oh My Zsh先说说我的真实经历。我最早用终端就是系统自带的Bash,黑底白字,看起来没什么问题,直到有一次在同事的工位上瞥见他那台机器:命令提示符里直接显示Git分支名称&…

2026/10/17 5:21:24 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/16 21:54:38 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →