人工智能语音音频深度学习NLP【免费下载链接】espnetEnd-to-End Speech Processing Toolkit项目地址https://gitcode.com/gh_mirrors/es/espnet点击查看免费下载本文以egs2/owsm_v1/s2t1食谱recipe的官方数据准备指南README.md为核心完整解析 OWSMOmni Whisper-style Speech Model论文编号 arXiv:2309.13876v1 版多语料 ASR 语料的准备方式如何用 local/data.sh 按 v1→v2→v3 渐进式构建合并语料、如何修改 db.sh 指定语料路径、作者推荐的“分语料提特征再合并”的实操流程以及 run.sh 到 s2t.sh 的完整 15 阶段训练解码流水线与模型配置。读完本文你可以独立复现 OWSM v1 的数据准备、特征转储与 S2Tspeech-to-text训练全流程。1. 背景OWSM v1 s2t1 食谱在仓库中的位置OWSM 项目将大规模多语言 ASR 语料组织为 v1/v2/v3 三个递进版本。v1 食谱位于 egs2/owsm_v1/s2t1属于 ESPnet2 的 S2T语音到文本任务与 espnet2 框架中的espnet2.bin.s2t_train/espnet2.bin.s2t_inference等入口对应。目录中的关键文件包括local/data.sh集中式数据准备脚本是所有 prepare 脚本的调度器local/prepare_*.sh 与 local/prepare_*.pyaishell、covost2、gigaspeech、librispeech、must-c、spgispeech、tedlium 等 v1 语料的逐语料准备脚本db.sh各语料的路径配置downloads表示可自动下载空值表示需手动准备s2t.shS2T 任务通用 15 阶段流水线run.sh 与 dump.sh训练与特征转储的入口示例conf/tuning/train_s2t_transformer_size768_e12_d12_lr1e-3_warmup10k.yaml 与 conf/decode_s2t.yaml训练与解码配置。2. 官方数据准备指南README 七条要点逐条展开README.md 给出了 7 条数据准备指导以下逐条结合仓库实现说明。(1) 按 v1 → v2 → v3 的顺序渐进准备。要获得完整的 v3 数据必须先准备 v1、v2、v3。入口命令为bash local/data.sh --VERSION v1 # 或 v2, v3从 local/data.sh 的源码看这一“渐进”不是口号而是硬依赖stage 2 合并 v2 数据时会检查data/train_v1、data/valid_v1是否存在若缺失则从兄弟食谱../../owsm_v1/s2t1/data/{train,valid}_v1复制第 171-178 行合并 v3 时同理会从../../owsm_v2/s2t1/data复制 v2 结果第 180-187 行。因此 v2/v3 阶段的 prepare 脚本实际位于egs2/owsm_v2/s2t1与egs2/owsm_v3/s2t1中v1 食谱内只提供 v1 语料的 prepare 脚本。(2) 运行local/data.sh前必须先修改db.sh。db.sh 中每个语料一个变量取值含义为downloads脚本可自动下载并解包如LIBRISPEECHdownloads、TEDLIUM3downloads、AISHELLdownloads、MUST_Cdownloads、TEDLIUM2downloads空值因许可问题无法自动下载需用户自行下载并填入本地路径如SPGISPEECH、COVOST2、GIGASPEECH、WSJ0、SWBD、VCTK相关受限语料等。v1 涉及的六个核心语料中AISHELL、LibriSpeech、MuST-C、TEDLIUM3 可自动下载而 GigaSpeech、SPGISpeech、CoVoST2 需要用户自行解决许可与下载问题。db.sh 末尾还包含针对特定机构环境CMU TIR、JHU的 hostname 判断分支自动改写 BABEL、WSJ 等语料路径。(3) 数据量巨大脚本不保证对每个语料都一次跑通遇到 bug 建议提 issue。(4) 该脚本只准备 train 和 valid 子集。测试数据需按常规 ESPnet2 格式单独准备。对应实现local/data.sh 中 v1 的valid_sets覆盖AISHELL-1/dev、CoVoST2/dev、GigaSpeech/DEV、LibriSpeech/dev-clean、LibriSpeech/dev-other、MuST-C_v1.2/v2/v3/dev、SPGISpeech/val、TEDLIUM3/dev并不包含任何 test split。(5) 强烈建议不要直接用合并后的train_v*/valid_v*做特征提取。作者推荐的做法是对每个语料分别运行 s2t.sh 的 stage 2-4特征转储阶段再把所有语料的数据目录合并到dump/raw下统一处理——这样便于同时处理所有语料检查与调试也更简单。官方实验正是这样做的。仓库中的 dump.sh 就是单语料CoVoST2转储特征的现成示例./s2t.sh \ --stage 3 \ --stop_stage 4 \ --use_lm false \ --ngpu 4 \ --nj 64 \ --gpu_inference true \ --inference_nj 8 \ --num_splits_s2t 1 \ --feats_type raw \ --audio_format flac.ark \ --token_type bpe \ --nbpe ${nbpe} \ --s2t_config ${s2t_config} \ --inference_config ${inference_config} \ --train_set ${train_set} \ --valid_set ${valid_set} \ --test_sets ${test_sets} \ --bpe_train_text data/${train_set}/text \ --bpe_nlsyms data/nlsyms.txt \ --lm_train_text data/${train_set}/text其中train_setCoVoST2/train、valid_setCoVoST2/dev。对照 s2t.sh 源码可知stage 3 将data/dset复制到dump/raw/org/dset并调用scripts/audio/format_wav_scp.sh把 unix-pipe 形式的wav.scp如sox xxx.mp3 ... |转成真实的 flac 文件/arkstage 4 把dump/raw/org/dset复制到dump/raw/dset并按--min_wav_duration 0.1/--max_wav_duration 30.5秒过滤长短语、删除空文本最后utils/fix_data_dir.sh保证各文件 utt 集合一致。(6)README 指向了一个官方 PRespnet/espnet#5478作为更多实现细节的参考local/data.sh 文件头注释也写明该脚本的细节与该 PR 一致可在仓库提交历史中检索该 PR 号。(7) 详细语料清单见local/data.sh并参考 OWSM 论文arXiv:2309.13876。3. v1/v2/v3 语料版本清单local/data.sh按--VERSION分支硬编码了三个版本要处理的语料与数据目录local/data.sh 第 60-135 行。v1本食谱 local/ 下提供的 prepare 脚本datasetsaishell、covost2、gigaspeech、librispeech、must-c、spgispeechtrain 数据目录data/AISHELL-1/train、data/CoVoST2/train、data/GigaSpeech/XL、data/LibriSpeech/train-clean-100/train-clean-360/train-other-500、data/MuST-C_v1.2/train、data/MuST-C_v2/train、data/MuST-C_v3/train、data/SPGISpeech/train、data/TEDLIUM3/trainvalid 数据目录AISHELL-1/dev、CoVoST2/dev、GigaSpeech/DEV、LibriSpeech/dev-clean、LibriSpeech/dev-other、MuST-C_v1.2/dev、MuST-C_v2/dev、MuST-C_v3/dev、SPGISpeech/val、TEDLIUM3/devv2语料更大位于 owsm_v2 食谱datasetsgigast、multilingual_librispeech、wenetspeechtraindata/GigaST/XL.en-*、data/MLS/train.*、data/WenetSpeech/Lvaliddata/MLS/dev.*、data/WenetSpeech/DEV依赖 v1 合并结果自动从 owsm_v1 复制train_v1/valid_v1参与合并v3多语扩展位于 owsm_v3 食谱datasetsaidatatang、ami、commonvoice、swbd、fisher_callhome、fleurs、ksponspeech、magicdata、reazonspeech、ru_open_stt、vctk、voxpopuli、wsj、voxforge、babel、openslrtraindata/ami/ihm_train_whisper、data/swbd/train_nodup_whisper、data/wsj/train_si284_whisper、data/voxforge/tr、data/babel/train、data/openslr/train等 16 个目录valid对应的*_whisper、FLEURS/valid、VoxPopuli/dev、voxforge/dt、babel/dev、openslr/dev等从命名结构看v3 中大量带_whisper后缀的目录如train_nodup_whisper、ihm_train_whisper可以推断是借助 Whisper 生成伪转录来标注这些无原生转写文本的语料data.sh 头部注释还说明AMI/SWBD/BABEL/OpenSLR 使用了新写的 data.sh 流程、AMI 与 VoxForge 的原始文本统一转成小写、ReazonSpeech 没有官方 train/valid/test 划分而是自行生成。此外v3 分支会在缺少./iso639目录时自动 clone 并安装 ISO-639 工具包data.sh 第 144-149 行因为 v3 数据统一采用 ISO-639-3 语言 ID合并 v3 前还会先用local/filter_lang_id.py把 v2 数据中的语言 ID 改写成 ISO-639-3第 188-196 行。4. data.sh 的执行机制详解local/data.sh 本身也是 stage 化脚本stage1、stop_stage2可通过--stage/--stop_stage覆盖并. ./path.sh与. ./db.sh加载环境。Stage 1逐语料准备。对${datasets}中的每个语料若存在data/.${dataset}.done标记文件则跳过断点续跑机制检查local/prepare_${dataset}.sh是否存在不存在则报错退出执行./local/prepare_${dataset}.sh成功后touch data/.${dataset}.done。Stage 2合并。关键变量为utt_extra_filestext.prev text.ctc输出目录为data/train_${VERSION}与data/valid_${VERSION}。合并流程utils/combine_data.sh --skip_fix true --extra-files text.prev text.ctc \ ${valid_out} ${valid_sets} utils/fix_data_dir.sh --utt_extra_files text.prev text.ctc ${valid_out} utils/validate_data_dir.sh --no-feats --non-print ${valid_out} # train 侧同理注意check_sorted函数data.sh 第 36-45 行合并后的text.prev、text.ctc必须按键排序且唯一否则会被就地重新排序。这是因为后续 S2T 训练把text.prev、text.ctc作为与 speech 对齐的额外文本通道见 s2t.sh 中同样定义的utt_extra_filestext.prev text.ctc第 331 行。5. prepare 脚本产出的 ESPnet2 数据结构以 local/prepare_librispeech.py 为典型样例逐语料 prepare 脚本会生成以下文件local/prepare_*.sh只是包装实际逻辑在对应.py中文件内容wav.scpwav-id wav-pathLibriSpeech 用 sox pipe 现场转 16k 单声道sox {mp3} -t wav -c 1 -r 16000 - \|segmentsutt-id wav-id start end把整段录音切成语句级片段textutt-id {lang}{task}{text_with_time}如带enasr前缀与时间戳符号的转写text.prev前句文本通道u.prev_text供模型预测上一句text.ctc用于 ASR CTC 分支的纯转写u.asr_text无特殊 tokenutt2spk说话人映射同时会写出nlsyms.txtnon-linguistic symbolsLibriSpeech 样例包含na、nospeech、en、asr及时间符号SYMBOLS_TIME。这份列表在训练时经--bpe_nlsyms传给spm_train的--user_defined_symbols保证这些任务/语言/时间 token 在 BPE 词表中不被切分。以 local/prepare_librispeech.sh 为例它固定处理dev-clean dev-other train-clean-100 train-clean-360 train-other-500五个 split调用local/prepare_librispeech.py --data_dir ${LIBRISPEECH} --prefix LibriSpeech随后对每个 split 执行check_sorted保证text.prev/text.ctc排序唯一、utils/fix_data_dir.sh --utt_extra_files text.prev text.ctc与utils/validate_data_dir.sh --no-feats --non-print。其余语料脚本如 prepare_gigaspeech.sh、prepare_must-c.sh、prepare_spgispeech.sh、prepare_covost2.sh、prepare_tedlium.sh、prepare_aishell.sh结构一致差异只在数据读取方式与 split 命名如 SPGISpeech 的 valid 目录叫val。local/下另有辅助脚本generate_nlsyms.py 汇总生成全局 nlsymsfilter_covost2.sh/filter_covost2.py 对 CoVoST2 做过滤remove_invalid_spaces.py、stats.py、utils.py定义Utterance、generate_long_utterances等被各 prepare 脚本共用的数据结构。6. 训练入口 run.sh 与 s2t.sh 流水线6.1 run.sh 的关键参数run.sh 在 s2t.sh 默认参数之上覆盖nbpe20000、--use_lm false不训练 LMs2t.sh 会自动跳过 stage 6-8、--ngpu 4 --nj 128、--gpu_inference true --inference_nj 4、--num_splits_s2t 5大语料分 5 份解析限制内存见 s2t.sh stage 11 的espnet2.bin.split_scps逻辑、--feats_type raw --audio_format flac.ark、--token_type bpe、--bpe_nlsyms data/nlsyms.txt、--bpe_train_text dump/raw/${train_set}/text。注意bpe_train_text指向dump/raw/...而非data/...与 README 第 (5) 条“分语料转储、合并于dump/raw”的做法一致。6.2 s2t.sh 的 15 个阶段s2t.sh 是完整流水线--stage/--stop_stage/--skip_stages控制执行范围--skip_data_prep/--skip_train/--skip_eval会批量追加跳过阶段第 520-541 行Stage内容关键命令1语料准备本食谱即local/data.shlocal/data.sh ${local_data_opts}2语速扰动未设置--speed_perturb_factors时跳过scripts/utils/perturb_data_dir_speed.shutils/combine_data.sh3特征准备raw 走format_wav_scp.sh生成 flac.arkfbank_pitch/extracted 走各自分支utils/copy_data_dir.sh、scripts/audio/format_wav_scp.sh4过滤过短/过长语音默认 0.1s–30.5s与空文本基于utt2num_samples/feats_shape的 awk 过滤 fix_data_dir.sh5BPE 训练spm_trainvocab_sizenbpeunigramtoken_list 首尾追加blank、unk、sos、eos、sopspm_train6-8LM 统计/训练/PPL--use_lm false时整体跳过espnet2.bin.lm_train、lm_calc_perplexity9n-gram 训练默认关lmplz/build_binary10S2T 统计收集多进程拆分 scp 并行 聚合espnet2.bin.s2t_train --collect_stats true、aggregate_stats_dirs11S2T 训练自动追加--normalizeglobal_mvn及feats_stats.npznum_splits_s2t1时先split_scps再--multiple_iterator trueespnet2.bin.launch --multiprocessing_distributed true -- espnet2.bin.s2t_train --resume true12解码按inference_nj拆分 keyGPU/CPU 可选--gpu_inference决定cuda_cmdvsdecode_cmdespnet2.bin.s2t_inference13评分char/word/bpe 三种粒度生成 trn 后用sclite算 WERscripts/utils/show_asr_result.sh输出RESULTS.mdespnet2.bin.tokenize_textsclite14模型打包espnet2.bin.pack s2t含 LM、feats_stats.npz、BPE 模型、nlsymspack_model15上传 HuggingFace默认--skip_upload_hf true跳过git git-lfsStage 11 中还有两点值得注意raw 特征会把s2t_speech_fold_length乘以 100 换算为帧单位_fold_length$((s2t_speech_fold_length * 100))即 800 帧 ≈ 16s16k/10ms hoptext.prev、text.ctc均以独立的--train_data_path_and_name_and_type .../text.prev,text_prev,text通道传入训练命令。7. 训练与解码配置解析7.1 训练配置 conf/tuning/train_s2t_transformer_size768_e12_d12_lr1e-3_warmup10k.yaml这是当前仓库conf/tuning/下实际提供的 S2T 训练配置要点如下preprocessor: s2tfs: 16000text_prev_name: text_prev与text_ctc_name: text_ctc与 s2t.sh 的utt_extra_files对应text_prev_apply_prob: 0.5、time_apply_prob: 0.5表示以 50% 概率启用前句/时间戳目标na_symbol: na、notime_symbol: notimestamps为禁用时的占位符speech_length: 30、speech_resolution: 0.02与 stage 4 的 30.5s 上限、10ms 帧移呼应。frontend_confSTFTn_fft: 512、win_length: 400、hop_length: 16016k 下 10ms 帧移。specaug2 条频率掩码宽度 0–27 维、5 条时间掩码宽度比 0–0.05关闭时域扭曲。encoder/decodertransformeroutput_size: 768、attention_heads: 12、linear_units: 3072、num_blocks: 12编码器input_layer: conv2d2normalize_before: true。model_confctc_weight: 0.3注意力CTC 联合训练与text.ctc通道配合、lsm_weight: 0.1。优化adamwlr 1e-3betas 0.9/0.98eps 1e-6warmuplrwarmup_steps: 10000。训练规模注释标明“4 GPU/node x 8 nodes 32 A100”batch_type: unsorted、batch_size: 64、accum_grad: 4、num_iters_per_epoch: 40000、max_epoch: 30、use_amp: true、keep_nbest_models: 5最优模型判据为valid/acc/max。注意run.sh 中引用的conf/tuning/train_s2t_transformer_lr1e-3_warmup5k.yaml与 dump.sh 引用的conf/tuning/train_s2t_ebf_lr1e-3_warmup5k.yaml并非仓库当前实际存在的文件conf/tuning/下现有的是 size768 这份实际使用时可通过--s2t_config指向任意存在的配置或用python -m espnet2.bin.s2t_train --print_config生成新配置模板。7.2 解码配置 conf/decode_s2t.yamlbeam_size: 1 penalty: 0.0 maxlenratio: 0.0 minlenratio: 0.0 ctc_weight: 0.0 lm_weight: 0.0 lang_sym: en task_sym: asr predict_time: falsebeam_size: 1即贪心解码不启用 LM/n-gramlang_sym: en、task_sym: asr与 prepare 脚本写入text的语言/任务前缀一致——推理时在 prompt 中拼接enasr即指示“英文 ASR”任务predict_time: false关闭时间戳预测。多语/多任务解码时这两个符号正是 OWSM 式“一个模型多任务”的核心机制训练语料AISHELL 的中文zh、CoVoST2 的翻译对、MuST-C 等由不同lang_sym/task_sym组合区分。8. 常见注意事项与适用前提许可受限语料必须手动就位db.sh中留空的变量GigaSpeech、SPGISpeech、CoVoST2 等需自行下载解压后填路径否则 stage 1 的对应 prepare 脚本会失败并中断data.sh 有|| exit 1。断点续跑stage 1 以data/.${dataset}.done为完成标记若某语料准备结果可疑需自行删除对应标记文件重跑本仓库为只读参考实际操作请在自己的检出目录中进行。只做 train/valid评估用 test 集要按 ESPnet2 常规格式wav.scp/segments/text等另行准备并可通过--test_sets传入 s2t.sh 的 stage 12-13。合并目录 vs 分语料转储README 明确反对直接用data/train_v*做特征提取推荐复制 dump.sh 的调用方式对每个语料跑 stage 3-4把结果汇总到dump/raw后再训练这样单个语料出问题可定位到具体目录。环境前提流水线依赖 ESPnet2 运行环境path.sh/cmd.sh加载 conda 环境、Kaldi 工具链sclite、utils/下的脚本、sentencepiecestage 5 的spm_train、humanfriendlystage 4 的采样数换算等v3 还需 ISO-639 工具包data.sh 会自动安装。规模参考size768 配置注释给出 32×A100、单 epoch 40000 步、30 epoch 的官方实验规模在小规模机器上可下调ngpu、batch_size并用num_iters_per_epoch控制每 epoch 步数。9. 小结OWSM v1 s2t1 食谱把“多语料渐进式准备”落到了具体脚本db.sh管路径、local/data.sh管调度与合并、local/prepare_*.sh管逐语料转换统一产出text/text.prev/text.ctc三通道结构、dump.sh/s2t.sh管特征转储与 15 阶段训练解码、conf/tuning与conf/decode_s2t.yaml管模型与解码行为。严格遵循 README 的七条指导——尤其是“先改 db.sh”“v1→v2→v3 顺序执行”“分语料转特征再合并到dump/raw”——即可在 ESPnet2 上复现 OWSM 多语言 ASR 的数据准备与训练全流程。赞分享人工智能语音音频深度学习NLP【免费下载链接】espnetEnd-to-End Speech Processing Toolkit项目地址https://gitcode.com/gh_mirrors/es/espnet点击查看免费下载相关推荐ESPnet2 S2T1 Recipe 实战指南基于弱监督学习与 OWSM 范式训练多任务 Speech-to-Text 模型ESPnet2 S2T1 Recipe 实战指南基于弱监督学习与 OWSM 范式训练多任务 Speech to Text 模型 本文围绕 ESPnet2 的人工智能语音音频深度学习NLPHaystack 音频转写指南使用 LocalWhisperTranscriber 与 RemoteWhisperTranscriber 构建语音转文本流水线Haystack 音频转写指南使用 LocalWhisperTranscriber 与 RemoteWhisperTranscriber 构建语音转文本流水线人工智能大模型RAGAI AgentNLPESPnet2 Recipe Template 实战指南用自有语料搭建 ASR/TTS 训练流程与 Kaldi 风格数据准备ESPnet2 Recipe Template 实战指南用自有语料搭建 ASR/TTS 训练流程与 Kaldi 风格数据准备 导读 ESPnet2 采用「任务人工智能语音音频深度学习NLP上一篇Bokeh 折线与曲线绘制全指南line、step、multi_line 与专用 glyph 实战下一篇KubeSphere DevOps 中 ArgoCD GitOps 的完整配置指南从安装、应用管理到多集群部署与排障创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
字节跳动全系云端产品完整梳理(2026 最新):从火山方舟到扣子的 TaoToken 统一接入配置指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 17:23:00
AI 工具测评与产品功能对比分析:用 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/9/25 17:23:00
2026年实测最值得推荐的5款AI智能降重工具 2026 年毕业季即将到来,各大高校对论文 AIGC 检测的要求愈发严格,这让不少同学在撰写论文时感到压力倍增。面对市面上种类繁多的降 AI 工具,到底该怎么选?我花了两周时间,对当前市面主流的 5 款降 AI 工具进行了全面测… · 2026/9/25 17:22:29
AI Agent 学习路线图:新手小白必收藏,用 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/9/25 18:00:33
警惕!低代码平台正在悄悄变成“新烟囱”——3个伪集成信号+避坑指南(TaoToken 统一 API 通道视角) /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 18:00:27
猫抓 cat-catch 浏览器媒体资源嗅探完整指南:网页视频预览与 M3U8 合并下载 猫抓 cat-catch 浏览器媒体资源嗅探完整指南:网页视频预览与 M3U8 合并下载 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch
猫抓&#… · 2026/9/25 18:00:15
AI_NovelGenerator 快速上手指南:从安装到写出第一个长篇章节 AI_NovelGenerator 快速上手指南:从安装到写出第一个长篇章节 【免费下载链接】AI_NovelGenerator 使用ai生成多章节的长篇小说,自动衔接上下文、伏笔 项目地址: https://gitcode.com/GitHub_Trending/ai/AI_NovelGenerator
AI_NovelGenerator 是… · 2026/9/25 18:00:03
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37