<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>博客 | VoicePing</title><link>https://voiceping.net/zh/blog/</link><description>Recent content in 博客 from VoicePing</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Thu, 16 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://voiceping.net/zh/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>多语言 OCR 基准测试：Hunyuan 与 Qwen 领先准确率，Paddle 领先吞吐量</title><link>https://voiceping.net/zh/blog/research-multilingual-ocr-gpu-benchmark-2026/</link><pubDate>Thu, 16 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-multilingual-ocr-gpu-benchmark-2026/</guid><description>&lt;p>&lt;strong>模型与参考资料：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.paddleocr.ai/latest/en/version3.x/algorithm/PP-OCRv5/PP-OCRv5_multi_languages.html">PaddleOCR PP-OCRv5&lt;/a>
 — 根据所选语言识别器，&lt;strong>活跃参数量为 310万至530万&lt;/strong>；面向移动端的检测-识别 OCR，可返回多边形和置信度。&lt;/li>
&lt;li>&lt;a href="https://github.com/JaidedAI/EasyOCR">EasyOCR&lt;/a>
 — 根据语言 reader，&lt;strong>活跃参数量为 2460万至7460万&lt;/strong>；使用 CRAFT 检测与 PyTorch 识别，返回文本区域和置信度。&lt;/li>
&lt;li>&lt;a href="https://mindee.github.io/doctr/latest/using_doctr/using_models.html">docTR&lt;/a>
 — 本次评估的预训练 predictor 含&lt;strong>2640万参数&lt;/strong>；两阶段 PyTorch 文档 OCR，可返回结构化区域和置信度。&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/zai-org/GLM-OCR">GLM-OCR&lt;/a>
 — &lt;strong>13.3亿参数&lt;/strong>；通过 Transformers 生成方式评估的视觉语言 OCR，用于纯文本和 Markdown 提取。&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/ibm-granite/granite-docling-258M">Granite Docling 258M&lt;/a>
 — &lt;strong>2.575亿参数&lt;/strong>；紧凑型 Transformers 文档转换模型，生成带版面位置的 DocTags。&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/abs/2511.19575">HunyuanOCR&lt;/a>
 — &lt;strong>11.2亿参数&lt;/strong>；面向文字定位、文档解析和语义文档任务的专用 OCR 视觉语言生成模型。&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/Qwen/Qwen3-VL-8B-Instruct">Qwen3-VL-8B-Instruct&lt;/a>
 — &lt;strong>87.7亿参数&lt;/strong>；用于多语言 OCR 与 Markdown 提取的通用视觉语言生成模型。&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/datalab-to/surya-ocr-2">Surya OCR 2&lt;/a>
 — &lt;strong>6.862亿参数&lt;/strong>；具备版面感知能力的 Transformers 生成模型，可输出带区域坐标的文本或 HTML。&lt;/li>
&lt;/ul>
&lt;p>参数量描述的是评估时实际启用的检查点权重，而不是下载文件大小。传统 OCR 的总数包含检测器与该页面所加载的语言专用识别器；生成模型使用公开检查点中的张量数量。&lt;/p>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们在同一套 900 页数据上评估了八个开源 OCR 系统：五种语言、六类图像，每个“语言×图像类型”单元包含 30 页。所有系统均在一张 NVIDIA RTX PRO 6000 Blackwell Max-Q GPU 上运行，并严格禁止自动回退到 CPU。&lt;/p></description></item><item><title>大规模说话人识别为何困难？五种模型的多语言开放集基准测试</title><link>https://voiceping.net/zh/blog/speaker-identification-multilingual-benchmark-2026/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/speaker-identification-multilingual-benchmark-2026/</guid><description>&lt;p>说话人识别基准往往强调很小的等错误率差异和模型排名。本研究把重点放在开放集系统真正需要作出的判断上：当探测语音的说话人可能未被注册时，排名第一的匹配是否足够强且足够明确，能够被系统接受。&lt;/p>
&lt;h2 id="核心结论">核心结论&lt;/h2>
&lt;p>当有4秒语音和4个注册样本时，五个模型的实际性能差异很小。在2秒条件下，ReDimNet-B6和w2v-BERT-SV构成领先组。ReDimNet的检查点规模较小，并且在主要留出评估以及干净条件和大图库辅助检验中都表现稳定，因此具有最强的综合研究依据。但这些证据仍不足以决定替换生产模型。&lt;/p>
&lt;p>最重要的运营结论是，拒绝判定必须针对每个模型单独校准。统一的余弦阈值比较的不只是说话人区分能力，还会比较尺度不同的嵌入空间。每个检查点都需要使用有代表性的开发身份来选择相似度阈值，以及第一名与第二名的分数间隔（margin）。&lt;/p>
&lt;p>下文将依次回答四个问题：语音很短时，哪些模型仍然可靠？有4秒语音时，模型差异是否仍然存在？应该如何拒绝未知说话人？综合准确率、计算量和许可证信息后，证据是否足以支持生产决策？&lt;/p>
&lt;h2 id="主要留出评估">主要留出评估&lt;/h2>
&lt;p>哪一项证据应该占据最大权重？身份分离的开放集比较是主要证据，因为它在比较全部五个模型的同时，将校准说话人与最终测试说话人分开。每种语言保留20个身份在图库中，并完全移除10个身份。移除身份中的5个用于选择相似度阈值和前两名分数的margin，另外5个则在设置不变的情况下进行测试。由此得到100人图库、25个开发未知身份，以及与开发集身份分离的25个测试未知身份。所有模型使用由哈希固定的同一组探测语音。&lt;/p>
&lt;p>开放集识别包含两个相互关联的判断：哪个注册说话人的相似度最高，以及该匹配是否足够可信、可以接受。本文报告等错误率（EER）、检测与识别率（DIR，即已知探测语音被正确识别且接受的比例），以及未知说话人的误接受率（FAR）。&lt;/p>
&lt;p>阈值和margin仅使用开发身份进行选择，要求开发未知身份的FAR不高于1%，然后原样应用于测试群组。置信区间使用2,000次按说话人聚类的bootstrap，另用50个确定性身份划分来测量结果对所选说话人的敏感度。这样的分离使留出评估成为本研究最可信的开放集证据。&lt;/p>
&lt;p>使用4个注册嵌入的代表性划分结果如下：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: right">探测时长&lt;/th>
 &lt;th>模型&lt;/th>
 &lt;th style="text-align: right">EER（95% CI）&lt;/th>
 &lt;th style="text-align: right">DIR（95% CI）&lt;/th>
 &lt;th style="text-align: right">观测测试 FAR&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: right">2s&lt;/td>
 &lt;td>ReDimNet-B6&lt;/td>
 &lt;td style="text-align: right">1.40% (0.54–1.98)&lt;/td>
 &lt;td style="text-align: right">&lt;strong>94.80% (91.60–97.60)&lt;/strong>&lt;/td>
 &lt;td style="text-align: right">1.60%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">2s&lt;/td>
 &lt;td>w2v-BERT-SV&lt;/td>
 &lt;td style="text-align: right">&lt;strong>1.05% (0.51–1.53)&lt;/strong>&lt;/td>
 &lt;td style="text-align: right">92.20% (87.80–96.00)&lt;/td>
 &lt;td style="text-align: right">1.20%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">2s&lt;/td>
 &lt;td>WeSpeaker R221-LM&lt;/td>
 &lt;td style="text-align: right">1.80% (0.75–2.81)&lt;/td>
 &lt;td style="text-align: right">89.60% (85.00–93.60)&lt;/td>
 &lt;td style="text-align: right">0.80%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">2s&lt;/td>
 &lt;td>ECAPA-TDNN&lt;/td>
 &lt;td style="text-align: right">2.20% (1.12–3.31)&lt;/td>
 &lt;td style="text-align: right">84.80% (79.80–89.20)&lt;/td>
 &lt;td style="text-align: right">0.80%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">2s&lt;/td>
 &lt;td>TitaNet-L&lt;/td>
 &lt;td style="text-align: right">2.22% (1.22–3.04)&lt;/td>
 &lt;td style="text-align: right">83.80% (78.20–88.80)&lt;/td>
 &lt;td style="text-align: right">2.00%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">4s&lt;/td>
 &lt;td>TitaNet-L&lt;/td>
 &lt;td style="text-align: right">0.60% (0.15–1.04)&lt;/td>
 &lt;td style="text-align: right">&lt;strong>98.80% (97.60–99.80)&lt;/strong>&lt;/td>
 &lt;td style="text-align: right">2.40%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">4s&lt;/td>
 &lt;td>ReDimNet-B6&lt;/td>
 &lt;td style="text-align: right">&lt;strong>0.20% (0.01–0.60)&lt;/strong>&lt;/td>
 &lt;td style="text-align: right">98.60% (97.20–99.60)&lt;/td>
 &lt;td style="text-align: right">0.00%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">4s&lt;/td>
 &lt;td>w2v-BERT-SV&lt;/td>
 &lt;td style="text-align: right">0.62% (0.11–1.39)&lt;/td>
 &lt;td style="text-align: right">98.40% (96.80–99.80)&lt;/td>
 &lt;td style="text-align: right">0.00%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">4s&lt;/td>
 &lt;td>WeSpeaker R221-LM&lt;/td>
 &lt;td style="text-align: right">0.60% (0.11–1.54)&lt;/td>
 &lt;td style="text-align: right">98.20% (96.20–99.60)&lt;/td>
 &lt;td style="text-align: right">1.20%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: right">4s&lt;/td>
 &lt;td>ECAPA-TDNN&lt;/td>
 &lt;td style="text-align: right">0.80% (0.20–1.42)&lt;/td>
 &lt;td style="text-align: right">97.80% (96.00–99.20)&lt;/td>
 &lt;td style="text-align: right">1.20%&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;img
 src="https://voiceping.net/zh/blog/speaker-identification-multilingual-benchmark-2026/heldout-risk-coverage-ci.zh.png"
 alt="带置信区间的留出未知说话人风险与正确识别覆盖"
 loading="lazy"
 decoding="async" width="1672" height="941">
&lt;/p></description></item><item><title>介绍 VoicePing Diarization v0.1</title><link>https://voiceping.net/zh/blog/research-diarization-commercial-api-benchmark-2026/</link><pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-diarization-commercial-api-benchmark-2026/</guid><description>&lt;h2 id="介绍-voiceping-diarization-v01">介绍 VoicePing Diarization v0.1&lt;/h2>
&lt;p>VoicePing Diarization v0.1 是我们首次公开发布的说话人分离模型：它面向多语言会议进行说话人分段，用来识别谁在什么时候发言，并为后续的说话人身份匹配做准备。&lt;/p>
&lt;p>本文通过 2026 年 7 月的一项 42 文件多语言基准介绍该模型。NeMo、pyannoteAI precision-2、AssemblyAI 和 Deepgram 也作为评估背景纳入其中，帮助读者理解 VoicePing Diarization v0.1 相对于常见开源方案和商业说话人标注方案的位置。&lt;/p>
&lt;p>有一点需要说明：VoicePing Diarization v0.1 是所选基准行的公开模型身份，并不是对生产模型注册表的实时检查。生产模型选择由运行时配置控制，生产系统还包含该纯说话人分离基准之外的下游说话人身份匹配。&lt;/p>
&lt;h2 id="评估设置">评估设置&lt;/h2>
&lt;p>该基准包含 42 个文件、约 10.5 小时音频：英语、日语、韩语、越南语和普通话五个单语集合，以及两个代码切换的多语言文件。场景从 30 秒到 1 小时不等，包含 2-9 名说话人和 0-30% 的重叠语音。&lt;/p>
&lt;p>这些文件是由真实单人录音拼接成的合成对话。因此它们拥有精确的参考标签和可重复的评分，但也比许多真实会议更干净。结果应被视为受控基准，而不是域外会议评估的替代品。&lt;/p>
&lt;p>评估集有意比原始内部导出更窄。NeMo 作为主要本地开源基线，使用重新运行产物中的 NeMo Neural MSDD 结果。pyannoteAI precision-2 作为最清晰的专用商业说话人分离服务。Deepgram 和 AssemblyAI 被纳入，是因为采购者在评估带说话人转写时经常比较它们，但被遮蔽的单元格不用于直接的标题排名。&lt;/p>
&lt;p>方法细节：DER 使用 pyannote.metrics 风格的说话人分离错误率计算，采用 fair collar，计入重叠语音，并按语料时长加权聚合。2026 年 7 月的研究评估导出使用了 &lt;code>voiceping-inc/titanet&lt;/code> Hugging Face 快照（&lt;code>titanet_finetuned.nemo&lt;/code>）中的 VoicePing Diarization v0.1 基准行、NeMo Neural MSDD 基线、pyannoteAI precision-2，以及 AssemblyAI 和 Deepgram 的 transcript 附带说话人标签输出。&lt;/p></description></item><item><title>VoicePing MT V0.1：英日AI翻译基准测试</title><link>https://voiceping.net/zh/blog/research-en-ja-translation-quality-benchmark/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-en-ja-translation-quality-benchmark/</guid><description>&lt;h2 id="introducing-voiceping-translation-model-mt-v01">Introducing VoicePing Translation Model MT V0.1&lt;/h2>
&lt;p>对全球团队来说，英语对话只有转成准确、完整、自然的日语，才能在日本真正发挥作用。本基准测试评估的就是这一实际任务：将英语源文本翻译成既保留含义又自然可读的日语。&lt;/p>
&lt;h2 id="概览">概览&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模型&lt;/th>
 &lt;th style="text-align: right">总分&lt;/th>
 &lt;th style="text-align: right">流畅度（Fluency）&lt;/th>
 &lt;th style="text-align: right">自然度（Naturalness）&lt;/th>
 &lt;th style="text-align: right">准确性（Accuracy）&lt;/th>
 &lt;th style="text-align: right">完整性（Completeness）&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>DeepL&lt;/td>
 &lt;td style="text-align: right">89.4&lt;/td>
 &lt;td style="text-align: right">91.1&lt;/td>
 &lt;td style="text-align: right">89.0&lt;/td>
 &lt;td style="text-align: right">88.7&lt;/td>
 &lt;td style="text-align: right">89.7&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Sakana Translate&lt;/td>
 &lt;td style="text-align: right">88.0&lt;/td>
 &lt;td style="text-align: right">86.7&lt;/td>
 &lt;td style="text-align: right">83.2&lt;/td>
 &lt;td style="text-align: right">88.5&lt;/td>
 &lt;td style="text-align: right">90.4&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>VoicePing MT v0.1&lt;/td>
 &lt;td style="text-align: right">87.2&lt;/td>
 &lt;td style="text-align: right">90.7&lt;/td>
 &lt;td style="text-align: right">87.5&lt;/td>
 &lt;td style="text-align: right">86.0&lt;/td>
 &lt;td style="text-align: right">86.8&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>GPT-5 mini&lt;/td>
 &lt;td style="text-align: right">87.0&lt;/td>
 &lt;td style="text-align: right">88.4&lt;/td>
 &lt;td style="text-align: right">85.5&lt;/td>
 &lt;td style="text-align: right">86.9&lt;/td>
 &lt;td style="text-align: right">87.1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Google Translate&lt;/td>
 &lt;td style="text-align: right">86.7&lt;/td>
 &lt;td style="text-align: right">87.1&lt;/td>
 &lt;td style="text-align: right">83.0&lt;/td>
 &lt;td style="text-align: right">86.4&lt;/td>
 &lt;td style="text-align: right">88.6&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Qwen3.6-27B-FP8 dequant&lt;/td>
 &lt;td style="text-align: right">86.3&lt;/td>
 &lt;td style="text-align: right">88.0&lt;/td>
 &lt;td style="text-align: right">84.9&lt;/td>
 &lt;td style="text-align: right">86.4&lt;/td>
 &lt;td style="text-align: right">86.2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Azure Translate&lt;/td>
 &lt;td style="text-align: right">79.2&lt;/td>
 &lt;td style="text-align: right">78.5&lt;/td>
 &lt;td style="text-align: right">73.3&lt;/td>
 &lt;td style="text-align: right">79.1&lt;/td>
 &lt;td style="text-align: right">82.6&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Llama 3.1 8B&lt;/td>
 &lt;td style="text-align: right">72.2&lt;/td>
 &lt;td style="text-align: right">71.7&lt;/td>
 &lt;td style="text-align: right">65.4&lt;/td>
 &lt;td style="text-align: right">72.8&lt;/td>
 &lt;td style="text-align: right">75.1&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="评估设置">评估设置&lt;/h2>
&lt;p>评估使用100条英语源文本。由于没有可信的日语标准译文，我们采用GPT-5.5逐模型评分。评审每次只看到英语原文和一个日语译文，不会看到其他模型输出或供应商名称。&lt;/p></description></item><item><title>VoicePing ASR Model V0.1 正式发布</title><link>https://voiceping.net/zh/blog/research-voiceping-asr-model-v01-benchmark/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-voiceping-asr-model-v01-benchmark/</guid><description>&lt;h2 id="voiceping-asr-model-v01-正式发布">VoicePing ASR Model V0.1 正式发布&lt;/h2>
&lt;p>今天，我们正式发布 &lt;strong>VoicePing ASR Model V0.1&lt;/strong>——我们面向 VoicePing 中最常用语言打造的多语言语音转文字模型，覆盖&lt;strong>英语、日语、韩语、中文和越南语&lt;/strong>五种语言。&lt;/p>
&lt;p>VoicePing 的核心是多语言语音沟通：会议、活动、语音翻译、转写文本、摘要与搜索。在这些工作流程中，自动语音识别（ASR）并不是一个孤立的功能，而是整个产品体验的第一层。如果转写结果不稳定，后续每一个环节的价值都会随之打折。&lt;/p>
&lt;p>VoicePing ASR Model V0.1 正是为这一现实而设计。它聚焦于我们服务最多的五种核心语言，目标是为真实对话生成更干净的转写文本。&lt;/p>
&lt;h2 id="一个模型胜任多语言场景">一个模型，胜任多语言场景&lt;/h2>
&lt;p>通用语音识别技术进步很快，但真实的多语言音频仍然存在不少难点：&lt;/p>
&lt;ul>
&lt;li>日语、韩语和中文需要针对语言特性的文本处理。&lt;/li>
&lt;li>越南语高度依赖准确的声调符号和词语边界。&lt;/li>
&lt;li>较长或嘈杂的音频片段容易出现转写不完整、输出为空或文本重复的问题。&lt;/li>
&lt;li>云端模型在不同语言上的表现可能差异很大，即使 API 接口看起来是统一的。&lt;/li>
&lt;li>在公开基准测试中表现出色的系统，未必最适合会议、活动和语音翻译场景。&lt;/li>
&lt;/ul>
&lt;p>VoicePing ASR Model V0.1 是我们围绕这五种语言的产品场景打造的首个整合模型。下面的基准测试要回答的是一个非常实际的问题：它对用户真正关心的语音，转写效果究竟如何？&lt;/p>
&lt;h2 id="它能做什么">它能做什么&lt;/h2>
&lt;p>VoicePing ASR Model V0.1 可以转写以下语言的语音：&lt;/p>
&lt;ul>
&lt;li>英语&lt;/li>
&lt;li>日语&lt;/li>
&lt;li>韩语&lt;/li>
&lt;li>中文&lt;/li>
&lt;li>越南语&lt;/li>
&lt;/ul>
&lt;p>其输出的转写文本，是 VoicePing 后续功能的基础，包括翻译、字幕、会议纪要以及可搜索的对话历史。&lt;/p>
&lt;p>本文中 &lt;strong>ASR&lt;/strong> 与 &lt;strong>STT&lt;/strong> 可互换使用，两者均指语音转文字（Speech-to-Text）转写。&lt;/p>
&lt;h2 id="评测">评测&lt;/h2>
&lt;h3 id="数据集">数据集&lt;/h3>
&lt;p>本次评测使用 VoicePing 的多语言语音测试集，每种语言 1,000 条音频片段，总时长约 41 小时。这些片段反映了 VoicePing 在实际使用中处理的语音类型：真实对话，而非干净的朗读录音。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>语言&lt;/th>
 &lt;th style="text-align: right">片段数&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>英语&lt;/td>
 &lt;td style="text-align: right">1,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>日语&lt;/td>
 &lt;td style="text-align: right">1,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>越南语&lt;/td>
 &lt;td style="text-align: right">1,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>韩语&lt;/td>
 &lt;td style="text-align: right">1,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>中文&lt;/td>
 &lt;td style="text-align: right">1,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>合计&lt;/strong>&lt;/td>
 &lt;td style="text-align: right">&lt;strong>5,000&lt;/strong>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>所有系统均在同一套音频上进行测试。&lt;/p></description></item><item><title>VoicePing 为东京 MedTech ROUND Pitch Day 提供实时英日翻译</title><link>https://voiceping.net/zh/blog/medtech-round-2026/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/medtech-round-2026/</guid><description>&lt;h1 id="voiceping-为东京-medtech-round-pitch-day-提供实时英语到日语翻译">VoicePing 为东京 MedTech ROUND Pitch Day 提供实时英语到日语翻译&lt;/h1>
&lt;p>&lt;em>九家医疗器械初创企业用英语进行路演。会场中的日本医生、工程师和制造商代表，则通过自己的手机和现场屏幕实时用日语跟进内容。&lt;/em>&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/medtech-round-2026/hero.jpg"
 alt="MedTech ROUND Pitch Day 主舞台上，一家初创企业正在用英语路演，旁边的第二块屏幕同步显示实时日语翻译。"
 loading="lazy"
 decoding="async" width="1600" height="1200">

&lt;em>主屏幕上是英语路演，左侧第二块屏幕同步显示实时日语翻译。&lt;/em>&lt;/p>
&lt;h2 id="活动概况">活动概况&lt;/h2>
&lt;p>MedTech ROUND Pitch Day 于 2026 年 5 月 28 日星期四在东京中城八重洲（Tokyo Midtown Yaesu）5 层活动空间举行，场地可俯瞰东京站。这是 MedTech ROUND 的 Demo Day。MedTech ROUND 是面向医疗器械初创企业的加速项目，由东京大学 Tokyo Biodesign 项目运营，并获得日本经济产业省（METI）和日本医疗研究开发机构（AMED）支持。&lt;/p>
&lt;p>登上这个舞台的门槛很高。约 80 家初创企业报名，12 家入选项目，最终有 9 家在当天进行路演。现场观众包括约 15 家医疗器械企业：既有作为项目企业合作伙伴的日本及全球领先制造商，也有投资人和项目运营团队。会场座无虚席。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/medtech-round-2026/media/event-title-slide.jpg"
 alt="MedTech ROUND Pitch Day 标题页，显示东京大学、Tokyo Biodesign、METI 和 AMED 为项目支持方。"
 loading="lazy"
 decoding="async" width="1200" height="1000">

&lt;em>该项目由东京大学 Tokyo Biodesign、METI 和 AMED 支持。&lt;/em>&lt;/p>
&lt;h2 id="面临的挑战">面临的挑战&lt;/h2>
&lt;p>整场活动以英语进行。九家初创企业全部使用英语路演，这是会场中全球制造商和国际嘉宾之间的共同语言。但这些企业最希望直接触达的许多人，包括日本医疗器械制造商、临床医生和投资人，主要用日语思考和工作。如果英语信息没有被充分理解，路演的价值也会随之打折。&lt;/p>
&lt;p>医疗器械路演本身也很难翻译。内容高度密集，涉及解剖学、临床操作、器械机制、监管术语，以及疾病和技术名称。这些正是通用翻译工具最容易出错的词。在这个会场里，专业术语就是路演的核心。术语传达准确，路演信息才真正传达出去。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/medtech-round-2026/media/venue-room.jpg"
 alt="东京 Midtown Yaesu 的活动空间，Pitch Day 开始前会场已经布置完成，可看到东京站方向。"
 loading="lazy"
 decoding="async" width="1600" height="1200">

&lt;em>东京中城八重洲 5 层活动空间，观众入场前的现场。&lt;/em>&lt;/p></description></item><item><title>VoicePing 在京都 JPCA 2026 提供实时双语翻译</title><link>https://voiceping.net/zh/blog/jpca-2026/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/jpca-2026/</guid><description>&lt;h1 id="voiceping-在京都-jpca-2026-提供实时双向翻译">VoicePing 在京都 JPCA 2026 提供实时双向翻译&lt;/h1>
&lt;p>&lt;em>来自加拿大的演讲嘉宾使用英语，日本医生使用日语。VoicePing 让会场中的每个人都能用自己的语言实时跟上同一场研讨会。&lt;/em>&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/jpca-2026/hero.jpg"
 alt="主屏幕上显示加拿大讲座的英文幻灯片，下方同步显示实时日语字幕。"
 loading="lazy"
 decoding="async" width="1600" height="853">

&lt;em>英语演讲在主屏幕上实时显示日语字幕。&lt;/em>&lt;/p>
&lt;h2 id="活动概况">活动概况&lt;/h2>
&lt;p>第 17 届日本基层医疗联合学会学术大会（JPCA 2026）于 2026 年 5 月 29 日至 31 日在京都国际会议中心举行。大会主题为 &amp;ldquo;Collaborating for Care. Connecting for Change.&amp;quot;。VoicePing 为 5 月 30 日星期六的一场重点研讨会提供支持。&lt;/p>
&lt;p>当前，基层医疗在日本的重要性日益突出。日本约三分之一人口为老年人，许多患者同时面对多种健康问题，医疗服务差距也在扩大。因此，一线医生在日常诊疗中的作用比以往任何时候都更关键。日本基层医疗也在积极借鉴海外经验，而加拿大是家庭医学领域经常参考的国家之一。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/jpca-2026/media/theme-slide.jpg"
 alt="主舞台屏幕上显示大会主题：Collaborating for Care. Connecting for Change."
 loading="lazy"
 decoding="async" width="1600" height="1200">

&lt;em>主舞台屏幕上的大会主题。&lt;/em>&lt;/p>
&lt;h2 id="面临的挑战">面临的挑战&lt;/h2>
&lt;p>这场研讨会采用双语形式。来自加拿大的教授使用英语发言，日本基层医疗医生使用日语发言。即使是事先准备好的演讲，现场翻译也并不容易。医学术语高度精确，翻译中很小的偏差都可能改变原意。&lt;/p>
&lt;p>真正的难点出现在最后。研讨会以英日交替的现场问答和小组讨论收尾。在这种讨论中，语言会不断切换。有人用日语提问，加拿大教授用英语回答，另一位小组成员再加入讨论，没有人能提前知道下一句会是哪种语言。&lt;/p>
&lt;p>要在现场准确翻译这样的对话并不简单。单一口译员可能难以跟上快速往返的节奏。只支持单向翻译的工具，也无法应对不断切换语言的讨论。普通翻译工具还可能在关键医学术语上出错，而这些术语恰恰最重要。&lt;/p>
&lt;h2 id="voiceping-的做法">VoicePing 的做法&lt;/h2>
&lt;p>VoicePing 以自动语言识别的双语模式支持整场研讨会。系统不固定为某一个翻译方向，而是自动识别正在使用的语言，并按正确方向进行翻译。英语实时转为日语，日语也实时转为英语。小组讨论来回切换时，不需要任何人手动调整方向。&lt;/p>
&lt;p>VoicePing 支持 48 种语言。在这个会场中，真正需要的是英语和日语。&lt;/p>
&lt;p>参会者可以选择最适合自己的方式跟进内容。有些人扫描二维码，在自己的手机上用所需语言阅读翻译，无需安装应用；也有人通过会场共享屏幕查看翻译。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/jpca-2026/media/screen-funding-ja-captions.jpg"
 alt="加拿大讲座的一页幻灯片在主屏幕上显示，下方同步滚动实时日语字幕。"
 loading="lazy"
 decoding="async" width="1600" height="896">

&lt;em>加拿大讲座的幻灯片在展示的同时，被实时翻译成日语显示在屏幕上。&lt;/em>&lt;/p>
&lt;h2 id="现场效果">现场效果&lt;/h2>
&lt;p>真正的考验是现场小组讨论，而系统顺利完成了任务。由于系统能够自动识别语言，语言切换时不需要人工介入。用日语提出的问题可以由英语回答，英语回答也能实时以日语显示在屏幕上，整个过程无需调整任何设置。&lt;/p>
&lt;p>整场研讨会中，两个方向的翻译都持续运行。加拿大教授发言时，屏幕同步显示实时日语字幕；日本医生发言时，也同样实时显示为英语。参会者不再等待翻译，而是自然地跟上讨论。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/jpca-2026/media/speaker-on-screen.jpg"
 alt="京都 JPCA 2026 主舞台屏幕上的演讲者。"
 loading="lazy"
 decoding="async" width="1600" height="1020">

&lt;em>主屏幕上的演讲者：会场视角下的研讨会现场。&lt;/em>&lt;/p>
&lt;h2 id="为什么重要">为什么重要&lt;/h2>
&lt;p>日本基层医疗正在把世界各地的优秀实践带给服务老龄化社会的一线医生。前提是语言不能成为阻碍。当翻译能够跟上对话节奏时，人们就不再关注语言本身，而是专注于医学内容。&lt;/p>
&lt;p>这正是 VoicePing 的价值所在：让同一个会场中的人即使不使用同一种语言，也能彼此沟通。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/jpca-2026/media/event-signboard.jpg"
 alt="京都国际会议中心外的 JPCA 2026 指示牌。"
 loading="lazy"
 decoding="async" width="1200" height="1600">

&lt;em>京都国际会议中心外的大会指示牌。&lt;/em>&lt;/p></description></item><item><title>没有逐字稿的炉边对谈：VoicePing 为 Early-Stage Deep Tech Forum 提供实时日英翻译</title><link>https://voiceping.net/zh/blog/deep-tech-forum-2026/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/deep-tech-forum-2026/</guid><description>&lt;h1 id="没有逐字稿的炉边对谈voiceping-为-early-stage-deep-tech-forum-提供实时日英翻译">没有逐字稿的炉边对谈：VoicePing 为 Early-Stage Deep Tech Forum 提供实时日英翻译&lt;/h1>
&lt;p>&lt;em>来自海外的机器人和量子领域创始人，与日本投资人、研究人员和政策相关人士同处一室。演讲和开放问答在两种语言之间展开，VoicePing 在发言发生的同时完成现场翻译。&lt;/em>&lt;/p>
&lt;h2 id="论坛tib-的一场早期深科技之夜">论坛：TIB 的一场早期深科技之夜&lt;/h2>
&lt;p>从人形机器人到量子技术，再到其他仍在从实验室走向商业化的新兴技术，深科技往往跨越国家和语言。创始人、投资人和研究人员并不总在同一地点，也未必使用同一种语言。对这样的活动来说，重要工作之一就是确保所有人都能跟上同一场对话。&lt;/p>
&lt;p>2026 年 5 月 27 日，这场对话在东京丸之内的 Tokyo Innovation Base（TIB）举行，活动名称为 &lt;strong>Early-Stage Deep Tech Forum [Robotics, Quantum &amp;amp; Emerging Technologies]&lt;/strong>。论坛时间为 &lt;strong>17:30 至 20:00&lt;/strong>，由 &lt;strong>Deloitte Tohmatsu&lt;/strong> 和 &lt;strong>MFV Partners&lt;/strong> 主办，并与 &lt;strong>Morning Pitch Asia&lt;/strong> 合作。晚间环节包括主题演讲、演示、炉边对谈、现场问答和交流。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/deep-tech-forum-2026/media/fireside-room.jpg"
 alt="Tokyo Innovation Base 的炉边对谈现场，VoicePing 实时翻译显示在小组旁边的屏幕上。"
 loading="lazy"
 decoding="async" width="1600" height="1200">

&lt;em>炉边对谈现场，VoicePing 的实时日英翻译显示在旁边的会场屏幕上。&lt;/em>&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/deep-tech-forum-2026/media/room-dual-screens.jpg"
 alt="Tokyo Innovation Base 会场全景：参会者面向两块大屏幕，一块显示演讲者幻灯片，另一块显示 VoicePing 实时英日翻译。"
 loading="lazy"
 decoding="async" width="1600" height="1200">

&lt;em>会场中的两块屏幕：一块显示幻灯片，另一块显示 VoicePing 实时翻译。&lt;/em>&lt;/p>
&lt;h2 id="挑战没有逐字稿的现场对话">挑战：没有逐字稿的现场对话&lt;/h2>
&lt;p>嘉宾需要跨越语言边界展开讨论。&lt;strong>Karthee Madasamy&lt;/strong>（&lt;strong>MFV Partners&lt;/strong> 管理合伙人）担任主持。台上嘉宾包括 &lt;strong>Agility Robotics&lt;/strong> 联合创始人兼董事长 &lt;strong>Damion Shelton&lt;/strong>，以及 &lt;strong>Asteria&lt;/strong> 创始人兼 CEO &lt;strong>Yoichiro Hirano&lt;/strong>：一位美国机器人公司创始人和一位日本软件公司创始人，面对的主要是日本观众。&lt;/p></description></item><item><title>UNLEASH Insights 2026：为赴印日本投资者代表团提供实时AI翻译</title><link>https://voiceping.net/zh/blog/case-study-unleash-capital-insights-2026/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/case-study-unleash-capital-insights-2026/</guid><description>&lt;p>VoicePing · Customer Story  ·  UNLEASH2026&lt;/p>
&lt;p>当一家日本风险投资基金带着投资者前往印度参加为期数天的峰会时，现场天然就是双语环境：项目在印度展开，观众则以日本人为主。UNLEASH Capital Partners在UNLEASH Insights 2026上正面临这样的场景，并首次采用了VoicePing的实时AI翻译，覆盖两天的小组讨论、演讲和问答环节。&lt;/p>
&lt;p>我们与UNLEASH Capital Partners的Sowmya Arunkumar进行了交流，了解他们为什么选择VoicePing、现场如何使用、哪些地方效果不错，以及坦率地说，哪些方面仍需要改进。我们保留了她直接、真实的反馈，因为她提出的愿望清单，正是我们正在推进的产品路线图。&lt;/p>
&lt;h2 id="活动与语言障碍">活动与语言障碍&lt;/h2>
&lt;h4 id="-能否先介绍一下自己以及unleash-insights-2026是什么样的活动">— 能否先介绍一下自己，以及UNLEASH Insights 2026是什么样的活动？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 我在UNLEASH担任顾问，负责影响力投资论点的构建与报告，同时也参与投资组合管理。我是在2025年12月加入的。我们5月安排了一场活动，大约有30到40位日本代表来到印度，我就是因为这场活动联系了VoicePing。活动主要介绍我们在印度所做的事情，包括我们的投资方向，以及围绕投资组合公司的讨论。整体形式包括小组讨论、一对一演示，以及贯穿全程的问答。&lt;/p>
&lt;h4 id="-语言方面的挑战是什么">— 语言方面的挑战是什么？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 大多数代表听英语也还可以，但用日语理解起来会更从容。因此，我们希望他们能够跟上各个环节中正在发生和讨论的内容。&lt;/p>
&lt;h2 id="为什么选择voiceping">为什么选择VoicePing&lt;/h2>
&lt;h4 id="-是什么让你们选择了voiceping">— 是什么让你们选择了VoicePing？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 我们调研了印度本地可用的很多工具。主要担心的是，在小组讨论中，很多工具通常无法准确拾取每位发言人的声音和表达，因此翻译结果并不正确。这也是我们在用户评价里看到的主要问题。也有头戴式耳机或耳机方案，但给35到40个人分发这些设备，对我们来说并不合理，所以我们需要一个符合需求的软件方案。&lt;/p>
&lt;h4 id="-其他方案如何">— 其他方案如何？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 收费模式不适合我们。对一天的活动来说价格偏高，而且大多是订阅制，例如50小时或100小时套餐。对于一次性活动来说，这没有意义。这是一个年度活动，我们只在那个时候需要翻译，并不是日常使用。&lt;/p>
&lt;h4 id="-你们是怎么找到我们的">— 你们是怎么找到我们的？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 是通过推荐。我们的Managing Partner Natsuki Sugai先生从一位在日本用过VoicePing的朋友那里听说了这款产品。那位朋友说，VoicePing在过去两年进步很大，建议我们试试看。于是我就联系了VoicePing团队。&lt;/p>
&lt;h2 id="现场如何使用">现场如何使用&lt;/h2>
&lt;h4 id="-现场翻译在两天会议期间通过主屏幕旁边的会场显示器实时展示团队在设置过程中是否有帮助">— 现场翻译在两天会议期间，通过主屏幕旁边的会场显示器实时展示。团队在设置过程中是否有帮助？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 有，团队从头到尾都很支持。他们帮助我们下载软件，也和场地的AV团队一起在会场里做了几次测试。活动当天，Aaron也整天在现场协助我们。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/unleash-capital-insights-2026/panel-translation-monitor.webp"
 alt="会场显示器上展示VoicePing翻译的小组讨论"
 loading="lazy"
 decoding="async" width="1600" height="1049">
&lt;/p>
&lt;h4 id="-价格方案是否容易配合你们的需求">— 价格方案是否容易配合你们的需求？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 是的。第一次通话时，团队解释了适用于一天或两天活动的套餐，这非常有帮助。我们也在那次通话中看了演示，这让我们确信它适合我们。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/unleash-capital-insights-2026/translation-monitor-closeup.webp"
 alt="会场显示器上显示的VoicePing日语翻译"
 loading="lazy"
 decoding="async" width="1600" height="1199">
&lt;/p>
&lt;h2 id="活动当天有效之处与不足之处">活动当天：有效之处与不足之处&lt;/h2>
&lt;h4 id="-翻译质量如何">— 翻译质量如何？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 英语到日语还可以。但有一场会议中，有人用日语发言，需要翻译成英语，那部分确实没有达到预期。我不懂日语，所以完全依赖翻译内容。有些时候，出来的英文内容并不准确。&lt;/p>
&lt;h4 id="-屏幕上的显示方式呢">— 屏幕上的显示方式呢？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 一个短语一旦翻译出来，就不应该再被反复改写。我读完一句并理解了它，但当我准备看下一句时，前一行已经变了，意思就丢失了。这让人困惑，而且节奏太快，很难跟上。&lt;/p>
&lt;p>— 这是非常合理的反馈。日语和英语的语序几乎相反，日语句子的意思往往要等到句尾动词出现后才完全确定。因此，早期生成的英文译文可能会在句子中途被修正。这是我们已经认识到的限制，我们正在开发一个减少文字闪动的新模型。在通话中，我们也展示了分屏视图，可以把已经稳定下来的内容固定在实时文本旁边。&lt;/p>
&lt;h4 id="-观众整体反馈如何">— 观众整体反馈如何？&lt;/h4>
&lt;p>&lt;strong>Sowmya:&lt;/strong> 比什么都没有要好。参会者用日语会更舒服，翻译也帮助他们跟上现场正在发生的内容。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/unleash-capital-insights-2026/audience-session.webp"
 alt="观看UNLEASH Insights 2026会议的观众"
 loading="lazy"
 decoding="async" width="1600" height="830">
&lt;/p></description></item><item><title>情感 TTS 基准测试：Qwen3-TTS、CosyVoice、IndexTTS-2、Fish Audio 与 VoxCPM 在日语和中文上的表现</title><link>https://voiceping.net/zh/blog/research-ja-zh-emotional-tts-benchmark/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-ja-zh-emotional-tts-benchmark/</guid><description>&lt;p>&lt;strong>模型与参考资料：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice">Qwen3-TTS CustomVoice 1.7B&lt;/a>
 - 支持显式情绪提示的自定义音色 TTS。&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/html/2412.10117v2">CosyVoice 300M Instruct / CosyVoice2&lt;/a>
 - instruction 风格 TTS 基线，带日语和中文内置说话人。&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/fishaudio/s1-mini">Fish Audio S1-mini&lt;/a>
 - 使用内联情绪标记的表现力 TTS 模型。&lt;/li>
&lt;li>&lt;a href="https://github.com/OpenBMB/VoxCPM">VoxCPM2&lt;/a>
 - 多语言提示驱动 TTS 模型。&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/html/2506.21619v2">IndexTTS-2&lt;/a>
 - 本文作为日语/中文实验对比对象评估的情感零样本 TTS 模型。&lt;/li>
&lt;/ul>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本文评估了五个面向&lt;strong>日语和中文&lt;/strong>的情感文本转语音系统，目标情绪包括 &lt;code>neutral&lt;/code>、&lt;code>happy&lt;/code>、&lt;code>sad&lt;/code>、&lt;code>angry&lt;/code>、&lt;code>fear&lt;/code> 和 &lt;code>disgust&lt;/code>。评估使用语义中性的提示句，因此模型必须通过语音风格表达情绪，而不是依赖文本本身的情绪词。每个模型生成120个样本，五个完成模型共形成600个 WAV 文件的主基准语料。&lt;/p>
&lt;p>综合表现最均衡的候选模型是 &lt;strong>Qwen3-TTS CustomVoice 1.7B&lt;/strong>：在日语和中文文本输出可信的模型中，它拥有最好的综合 SenseVoice 准确率、最低平均 CER、最佳锚点命中率，以及较强的 NISQA-TTS 自然度。&lt;strong>CosyVoice 300M Instruct&lt;/strong> 是自然度领先者，但情绪识别较弱，尤其是在日语中。&lt;strong>IndexTTS-2&lt;/strong> 的综合 SenseVoice 分数较高，但日语 CER 过高，因此不能把该结果视为可靠的日语 TTS 证据。&lt;/p>
&lt;p>最重要的模式是语言和情绪的不平衡：在该自动评估设置下，中文始终比日语更容易，而 &lt;code>fear&lt;/code> 和 &lt;code>disgust&lt;/code> 在所有被评估模型中仍未解决。&lt;/p>
&lt;h2 id="动机">动机&lt;/h2>
&lt;p>情感 TTS 不只是自然度问题。模型可以听起来流畅、悦耳，却无法表达指定风格。对于多语言虚拟人、客服语音、训练模拟、富表现力语音翻译等产品场景，我们需要确认 TTS 系统能否同时保持三件事一致：&lt;/p></description></item><item><title>消除与韩国子公司的语言壁垒：支持Brave group全球VTuber业务扩展的实时翻译 - Brave group × VoicePing</title><link>https://voiceping.net/zh/blog/case-study-bravegroup/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/case-study-bravegroup/</guid><description>&lt;p>株式会社Brave group以VTuber业务为核心，同时开展受托开发、硬件企划与销售、集换式卡牌游戏等多元业务。该公司在欧洲、英语圈、泰国等世界各地设有据点，并运营多家子公司。2025年7月，Brave group与韩国最大级别的VTuber经纪公司StelLive完成经营整合。由此，公司在日常工作中需要进行韩语实时沟通，并因此引入了VoicePing。&lt;/p>
&lt;p>本次我们采访了主导VoicePing导入的集团管理本部 信息系统部部长西晃生先生，了解导入背景、具体使用场景以及未来展望。&lt;/p>
&lt;h2 id="案例要点">案例要点&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>课题：&lt;/strong> 与StelLive完成经营整合后，Brave group需要应对韩语实时翻译和多语言会议。&lt;/li>
&lt;li>&lt;strong>解决方案：&lt;/strong> 使用VoicePing在韩语、日语、英语、泰语等会议中进行实时翻译和会议转录。&lt;/li>
&lt;li>&lt;strong>效果：&lt;/strong> 口译负责人的负担降低，员工参加海外会议的心理门槛也下降。&lt;/li>
&lt;li>&lt;strong>适用场景：&lt;/strong> 韩语实时翻译、多语言会议、海外子公司沟通、VTuber活动的多语言支持。&lt;/li>
&lt;/ul>
&lt;p>对于正在评估韩语实时翻译或多语言会议转录的团队，本案例也可以作为&lt;a href="https://voiceping.net/zh/products/event-translation-app/">会议和活动实时翻译&lt;/a>
以及&lt;a href="https://voiceping.net/zh/products/virtual-office/">面向全球协作的虚拟办公室&lt;/a>
的参考。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/ja/bravegroup-nishi-profile.jpeg"
 alt="株式会社Brave group 集团管理本部 信息系统部部长 西晃生先生"
 loading="lazy"
 decoding="async" width="512" height="512">
&lt;/p>
&lt;p>&lt;em>株式会社Brave group 集团管理本部 信息系统部部长 西晃生先生&lt;/em>&lt;/p>
&lt;h2 id="以ip为核心进行全球扩展的娱乐企业">以IP为核心进行全球扩展的娱乐企业&lt;/h2>
&lt;p>&lt;strong>首先，请介绍一下您的职位以及Brave group的业务。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 我是株式会社Brave group的西。现在担任控股公司集团管理本部信息系统部部长。我们有很多子公司，最知名的业务是拥有VTuber的IP（知识产权）业务。我们运营着&amp;quot;ぶいすぽっ！&amp;ldquo;和&amp;quot;StelLive&amp;quot;等VTuber经纪公司。此外，还有受托开发业务、利用IP企划和销售键盘等硬件的业务，最近也开展了集换式卡牌游戏业务。业务范围很广，所以如果被问到&amp;quot;这是一家什么样的公司？&amp;ldquo;很难用一句话概括，但总体来说，我们是一家以IP为核心、以多种形式展开业务的公司。&lt;/p>
&lt;h2 id="与韩国企业的经营整合成为契机实时翻译变得迫切">与韩国企业的经营整合成为契机，实时翻译变得迫切&lt;/h2>
&lt;p>&lt;strong>请介绍一下导入VoicePing的契机。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 2025年7月，我们与韩国的StelLive（ステライブ）这家VTuber业务公司进行了经营整合。此前，我们已经在欧洲、英语圈、泰国等地设立海外据点，并主要使用英语运营，但韩国的情况有很大不同。实时交流时的主要语言不是英语，而是韩语。&lt;/p>
&lt;p>因此，我们开始寻找能够支持韩语的同声传译和转录工具，这就是最初的契机。&lt;/p>
&lt;p>&lt;strong>市面上还有很多翻译工具。当时的课题是什么？&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 首先，我们使用Google Workspace，所以也尝试过生成式AI的翻译功能。如果已经有文本，再让它读取并翻译，准确度非常好，但实时应对比较困难。&lt;/p>
&lt;p>另外，我们试用了几个工具后发现，很多工具会先把日语翻译成英语，再从英语翻译成韩语，也就是所谓的两阶段翻译。界面上看起来像是从日语直接翻译成韩语，但我们团队中也有会说韩语的成员，他们看翻译结果时，经常会觉得&amp;quot;语感好像有点别扭&amp;rdquo;。&lt;/p>
&lt;h2 id="选择voiceping的决定因素不同语言使用不同ai模型">选择VoicePing的决定因素：不同语言使用不同AI模型&lt;/h2>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/ja/bravegroup-logo.png"
 alt="Brave group标志"
 loading="lazy"
 decoding="async" width="3819" height="2444">
&lt;/p>
&lt;p>&lt;em>Brave group标志&lt;/em>&lt;/p>
&lt;p>&lt;strong>在这些工具中，为什么选择VoicePing？&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 在听VoicePing说明时，我们了解到调整语言时会使用不同的模型。我们认为这样应该不会出现此前感受到的两阶段翻译感，这成为了选择VoicePing的重要理由。&lt;/p>
&lt;p>实际请会说韩语的成员确认后，与其他工具相比，翻译的自然度也更好。&lt;/p>
&lt;h2 id="从后台部门到跨业务部门在多语言交织的现场使用">从后台部门到跨业务部门，在多语言交织的现场使用&lt;/h2>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/ja/bravegroup-voiceping-scene.png"
 alt="VoicePing双语模式中进行日语和韩语实时翻译的画面"
 loading="lazy"
 decoding="async" width="2910" height="1756">
&lt;/p>
&lt;p>&lt;em>VoicePing双语模式中进行日语和韩语实时翻译的画面。图片提供：株式会社Brave group&lt;/em>&lt;/p>
&lt;p>&lt;strong>具体在哪些场景中使用？&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 母公司Brave group控股公司本身负责后台业务和活动支持，是支持子公司的立场。有些IP来自海外，很多时候会由日本人成员在中间推进沟通。&lt;/p>
&lt;p>在这类会议中，不仅是韩语，我们也会在日语和英语组合的场景中使用VoicePing。例如，交易对象中有英语圈人士，日本的我们以及IP公司的工作人员也参加会议。当我们作为现场工作人员的沟通中介时，会议中就会出现多种语言。我们经常在这样的场景中使用。&lt;/p>
&lt;p>&lt;strong>也在韩语以外的语言中使用，是吗？&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 是的。似乎也有人在泰语场景中使用。虽然反馈还没有全部收集完，但在各种语言场景中的使用正在扩大。&lt;/p>
&lt;h2 id="口译成员负担大幅降低可以不再畏惧地参加会议">口译成员负担大幅降低：&amp;ldquo;可以不再畏惧地参加会议&amp;rdquo;&lt;/h2>
&lt;p>&lt;strong>导入后的效果如何？&lt;/strong>&lt;/p>
&lt;p>&lt;strong>西先生：&lt;/strong> 最大的效果是会说韩语的成员负担降低了。以前需要请他们实时口译，但导入VoicePing后，会先转成文字，再只请他们指出语感不同的地方。可以说工时和负担都明显降低了。&lt;/p>
&lt;p>另外，对日本员工来说也有很大变化。只要有账号，即使没有会说韩语的成员在场，也可以有一种前提：使用工具至少能够完成最低限度的沟通。因此，大家可以不再畏惧地参加海外会议。能够把注意力集中在会议的重要要点上推进，我认为这一点非常有效。&lt;/p></description></item><item><title>VoicePing在SusHi Tech Tokyo 2026 GLOBAL × SCALEUP TOKYO创业展示会上提供实时翻译</title><link>https://voiceping.net/zh/blog/case-study-sushitech-tokyo-2026-global-scaleup/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/case-study-sushitech-tokyo-2026-global-scaleup/</guid><description>&lt;h1 id="voiceping在sushi-tech-tokyo-2026-global--scaleup-tokyo上提供实时翻译">VoicePing在SusHi Tech Tokyo 2026 GLOBAL × SCALEUP TOKYO上提供实时翻译&lt;/h1>
&lt;p>VoicePing在作为&lt;strong>SusHi Tech Tokyo 2026 – Gathering Day&lt;/strong>一部分、于&lt;strong>Tokyo Innovation Base&lt;/strong>举办的**「GLOBAL × SCALEUP TOKYO SU生态系统：Global VC Insights &amp;amp; Startup Showcase」**上提供了实时AI翻译支持。来自世界各地的风险投资机构、企业VC以及东京最具前景的创业公司齐聚一堂，通过无缝多语言沟通实现了跨境对话。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/case-study-sushitech-2026-agenda.webp"
 alt="Tokyo Innovation Base主舞台上展示的活动议程"
 loading="lazy"
 decoding="async" width="1320" height="1760">

&lt;em>Tokyo Innovation Base的活动议程 — 包括Global Strategy Talk、Tokyo Startup Showcase以及深科技和绿色创业公司路演。&lt;/em>&lt;/p>
&lt;h2 id="活动概览全球vc与东京创业生态系统的交汇">活动概览：全球VC与东京创业生态系统的交汇&lt;/h2>
&lt;p>GLOBAL × SCALEUP TOKYO活动精心设计了丰富的议程，旨在将日本的创业生态系统与国际投资者和合作伙伴连接起来：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Global Strategy Talk（下午2:30）&lt;/strong> — 为跨境合作奠定基础的开场环节&lt;/li>
&lt;li>&lt;strong>小组讨论：&amp;ldquo;从海外VC/CVC视角看日本创业投资与全球扩张&amp;rdquo;&lt;/strong> — &lt;strong>Pegasus Tech Ventures&lt;/strong>、&lt;strong>Alumni Ventures&lt;/strong>和&lt;strong>Woven Capital&lt;/strong>的全球VC分享了对日本创业环境的坦率见解&lt;/li>
&lt;li>&lt;strong>Tokyo Startup Showcase（下午3:30）&lt;/strong> — 聚焦创新日本创业公司&lt;/li>
&lt;li>&lt;strong>路演环节：Deep Ecosystem / Green Startups（下午3:55）&lt;/strong> — 展示深科技和可持续发展领域的企业&lt;/li>
&lt;li>&lt;strong>SusHi Tech Tokyo 2026主要发布（下午5:00）&lt;/strong> — SusHi Tech Tokyo整体重要公告&lt;/li>
&lt;li>&lt;strong>社交活动（下午5:40~7:00）&lt;/strong> — 创始人与投资者跨越语言直接交流&lt;/li>
&lt;/ul>
&lt;p>本活动由&lt;strong>Startup Ecosystem Tokyo Consortium&lt;/strong>与&lt;strong>东京都政府&lt;/strong>合作，作为SusHi Tech Tokyo 2026计划的一部分举办。&lt;/p></description></item><item><title>VoicePing在JETRO Startup Alumni Meetup 2026上提供实时翻译 — 连接2,000多家初创企业</title><link>https://voiceping.net/zh/blog/case-study-jetro-startup-alumni-meetup-2026/</link><pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/case-study-jetro-startup-alumni-meetup-2026/</guid><description>&lt;h1 id="voiceping在jetro-startup-alumni-meetup-2026上提供实时翻译">VoicePing在JETRO Startup Alumni Meetup 2026上提供实时翻译&lt;/h1>
&lt;p>VoicePing在日本最大规模的创业生态系统活动**「JETRO Startup Alumni Meetup 2026」**上提供了实时AI翻译技术。2,000多家初创企业、风险投资机构和支持组织齐聚一堂，VoicePing的实时翻译消除了小组讨论、演讲和交流活动中的语言障碍。&lt;/p>
&lt;h2 id="活动概要日本创业生态系统大集结">活动概要：日本创业生态系统大集结&lt;/h2>
&lt;p>JETRO Startup Alumni Meetup 2026汇聚了JETRO旗舰加速器项目的校友——包括&lt;strong>AlchemistX&lt;/strong>、&lt;strong>500 Global&lt;/strong>和&lt;strong>硅谷扩展计划&lt;/strong>——以及广泛的风险投资机构、企业合作伙伴和政府组织。&lt;/p>
&lt;p>活动举办了以&lt;strong>AI、深科技、生物技术、融资和全球扩张&lt;/strong>为主题的高水平小组讨论，并设有大规模交流环节。来自不同国家和语言背景的参与者齐聚一堂，实时翻译对于确保每位参与者深度参与至关重要。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/case-study-jetro-startup-alumni-meetup-2026-venue.jpg"
 alt="JETRO Startup Alumni Meetup 2026会场，2,000多名参与者齐聚。"
 loading="lazy"
 decoding="async" width="1024" height="768">

&lt;em>JETRO Startup Alumni Meetup 2026会场。2,000多家初创企业、风险投资机构和支持组织共同活跃日本创业生态系统。&lt;/em>&lt;/p>
&lt;h2 id="挑战大规模活动中的语言障碍">挑战：大规模活动中的语言障碍&lt;/h2>
&lt;p>在2,000多名来自日本国内外的参与者齐聚的活动中，多个会议同时进行，需要实时多语言沟通。AI和深科技等前沿主题的小组讨论要求翻译具有准确性和细微差别，能够跟上专家之间快节奏的对话。&lt;/p>
&lt;p>传统的口译方式难以覆盖多个舞台和分会场，同时保持创业交流所必需的临场感和即时性。&lt;/p>
&lt;h2 id="voiceping的解决方案全场实时翻译">VoicePing的解决方案：全场实时翻译&lt;/h2>
&lt;p>作为JETRO加速器项目的骄傲校友，VoicePing承担了本次活动的实时翻译支持。参与者可以在自己的设备上访问实时翻译，无论演讲者使用何种语言，都能通过即时字幕观看小组讨论和演讲。&lt;/p>
&lt;p>VoicePing的翻译技术被部署在主舞台的演讲和小组讨论中，确保日本创业者与国际参与者能够双向无缝交流。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/case-study-jetro-startup-alumni-meetup-2026-panel-session.jpg"
 alt="「创新变革：应对挑战与全球扩张之路」小组讨论"
 loading="lazy"
 decoding="async" width="1024" height="768">

&lt;em>以「创新变革：应对挑战与全球扩张之路」为主题的小组讨论。VoicePing提供实时翻译支持。&lt;/em>&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/images/blog/en/case-study-jetro-startup-alumni-meetup-2026-voiceping-translation.jpg"
 alt="VoicePing实时翻译界面在活动现场运行"
 loading="lazy"
 decoding="async" width="1024" height="768">

&lt;em>活动现场运行的VoicePing实时AI翻译，为参与者即时提供多语言字幕。&lt;/em>&lt;/p>
&lt;h2 id="成果2000多人跨越语言障碍交流">成果：2,000多人跨越语言障碍交流&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>2,000多名参与者&lt;/strong>在日本最大规模的创业活动中跨越语言障碍交流&lt;/li>
&lt;li>&lt;strong>AI、深科技、生物技术、融资、全球扩张&lt;/strong>小组讨论可供所有参与者实时理解&lt;/li>
&lt;li>日本创业者与国际参与者在交流和问答环节中无缝对话&lt;/li>
&lt;li>零停机——VoicePing的翻译在多个会议中持续不间断运行&lt;/li>
&lt;/ul>
&lt;h2 id="voiceping作为jetro加速器校友的历程">VoicePing作为JETRO加速器校友的历程&lt;/h2>
&lt;p>VoicePing是JETRO的&lt;strong>AlchemistX&lt;/strong>、&lt;strong>500 Global&lt;/strong>和&lt;strong>硅谷扩展计划&lt;/strong>的校友。这些项目在VoicePing从日本初创企业成长为全球实时翻译平台的过程中发挥了重要作用。&lt;/p>
&lt;p>在Alumni Meetup上提供翻译支持，是利用JETRO生态系统诞生的技术连接下一代走向全球市场的初创企业的一个意义深远的回归原点。&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;看到我们的技术消除语言障碍，将日本创业者与全球参与者连接在一起——这正是我们创建VoicePing的原因。没有什么比看到自己的产品在实时中拉近人与人的距离更令人欣慰的了。&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;p>▼活动详情&lt;/p>
&lt;p>活动名称：JETRO Startup Alumni Meetup 2026&lt;/p>
&lt;p>主办方：JETRO（日本贸易振兴机构）&lt;/p>
&lt;p>地点：东京，日本&lt;/p>
&lt;p>参与者：2,000多家初创企业、风险投资机构和支持组织&lt;/p>
&lt;p>活动详情：https://luma.com/9zq2jvid&lt;/p>
&lt;h2 id="用voiceping将您的活动打造成无语言障碍的国际盛会">用VoicePing将您的活动打造成「无语言障碍的国际盛会」！&lt;/h2>
&lt;p>VoicePing通过快速、准确的实时翻译消除语言障碍，为来自不同国家和文化的参与者创造无缝交流的环境。&lt;/p>
&lt;p>📱 只需扫描二维码！在智能手机上轻松查看翻译内容。无论是演讲、路演还是交流活动，VoicePing都能确保顺畅沟通。&lt;/p>
&lt;p>使用VoicePing的优势：&lt;/p>
&lt;p>🌍 多国参与者以母语理解内容——所有会议中，参与者都能无语言障碍地深入理解。&lt;/p>
&lt;p>⚡ 简单操作与高精度翻译减轻负担——直观的界面和快速翻译大幅减少运营工作量。&lt;/p>
&lt;p>💡 提升参与者满意度和活动评价——利用翻译支持提高活动整体质量，获得参与者的积极反馈。&lt;/p></description></item><item><title>离线语音翻译应用：iOS/Android 跨平台端侧转写、翻译与 TTS</title><link>https://voiceping.net/zh/blog/research-offline-speech-translation-app/</link><pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-offline-speech-translation-app/</guid><description>&lt;p>&lt;strong>源代码：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/voiceping-ai/ios-android-offline-speech-translation">ios-android-offline-speech-translation&lt;/a>
 — 集成 ASR、翻译、TTS 和系统音频捕获的 iOS/Android 跨平台离线语音翻译应用（Apache 2.0）&lt;/li>
&lt;/ul>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们开发了一款开源跨平台移动应用，可在 iOS 和 Android 上实现完全离线的语音翻译。该应用将端侧自动语音识别（SenseVoice Small，通过 sherpa-onnx）、神经机器翻译（Apple Translation / Google ML Kit）和文本语音合成集成为统一管线。两个平台都支持麦克风和系统音频捕获——在平台捕获限制范围内，可以翻译来自其他应用（视频通话、媒体等）的音频，无需云端连接。端侧 ASR 在 iPad Pro（A12X）上达到 23.6 tok/s，在 Samsung Galaxy S10 上达到 33.6 tok/s（RTF &amp;lt; 0.1）。翻译和 TTS 阶段使用平台原生引擎，本次发布未进行单独基准测试。&lt;/p>
&lt;h2 id="研究动机">研究动机&lt;/h2>
&lt;p>完整的语音翻译管线（ASR、机器翻译、TTS）能否在 2018-2019 年的消费级手机上可靠地离线运行？端侧 AI 研究的基准测试通常单独评估各个模型，但实际应用需要将多个阶段串联起来，在平台沙箱限制下管理系统音频捕获，并处理完整的生命周期（持久化、导出、后台处理）。&lt;/p>
&lt;p>本项目验证的是系统可行性：整个管线能否在真实的消费级硬件上不依赖网络连接端到端运行。应用已开源，开发者可以直接评估架构设计。&lt;/p>
&lt;h2 id="应用概览">应用概览&lt;/h2>
&lt;h3 id="ios">iOS&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>首页&lt;/th>
 &lt;th>转写 + 翻译&lt;/th>
 &lt;th>演示&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;img
 src="https://raw.githubusercontent.com/voiceping-ai/ios-android-offline-speech-translation/main/docs/screenshots/ios-home.png"
 alt="iOS 首页"
 loading="lazy"
 decoding="async">
&lt;/td>
 &lt;td>&lt;img
 src="https://raw.githubusercontent.com/voiceping-ai/ios-android-offline-speech-translation/main/docs/screenshots/ios-transcription.png"
 alt="iOS 转写 &amp;#43; 翻译"
 loading="lazy"
 decoding="async">
&lt;/td>
 &lt;td>&lt;img
 src="https://raw.githubusercontent.com/voiceping-ai/ios-android-offline-speech-translation/main/docs/screenshots/ios-file-transcription-demo.gif"
 alt="iOS 演示"
 loading="lazy"
 decoding="async">
&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>SenseVoice Small 搭配 Apple Translation（英语 → 日语）和 TTS。&lt;/p>&lt;/blockquote>
&lt;h3 id="android">Android&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>转写 + 翻译&lt;/th>
 &lt;th>演示&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;img
 src="https://raw.githubusercontent.com/voiceping-ai/ios-android-offline-speech-translation/main/docs/screenshots/android_transcribe_translate.png"
 alt="Android 转写 &amp;#43; 翻译"
 loading="lazy"
 decoding="async">
&lt;/td>
 &lt;td>&lt;img
 src="https://raw.githubusercontent.com/voiceping-ai/ios-android-offline-speech-translation/main/docs/demos/android_speech_translation_demo.gif"
 alt="Android 演示"
 loading="lazy"
 decoding="async">
&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>SenseVoice Small 搭配 ML Kit 翻译和 TTS。&lt;/p></description></item><item><title>语音翻译：英日双向翻译中 Qwen3-ASR 与 Whisper 的对比</title><link>https://voiceping.net/zh/blog/research-speech-translation/</link><pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-speech-translation/</guid><description>&lt;p>&lt;strong>模型（Hugging Face）：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://huggingface.co/voiceping-ai/qwen3-asr-ja-en-speech-translation">voiceping-ai/qwen3-asr-ja-en-speech-translation&lt;/a>
 — 针对 EN↔JA 双向语音翻译微调的 Qwen3-ASR（1.7B 参数，评估中质量最高）&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/voiceping-ai/whisper-ja-en-speech-translation">voiceping-ai/whisper-ja-en-speech-translation&lt;/a>
 — 用于 EN↔JA 双向语音翻译的 Distilled Whisper（756M 参数，快 4 倍）&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>推理代码（GitHub）：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/voiceping-ai/qwen3-asr-ja-en-speech-translation">qwen3-asr-ja-en-speech-translation&lt;/a>
 — 推理脚本、评估流水线和模型使用示例&lt;/li>
&lt;li>&lt;a href="https://github.com/voiceping-ai/whisper-ja-en-speech-translation">whisper-ja-en-speech-translation&lt;/a>
 — 推理脚本、评估流水线和模型使用示例&lt;/li>
&lt;/ul>
&lt;p>训练脚本未包含在这些仓库中。&lt;/p>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本研究提出两个英日双向语音翻译模型：(1) &lt;strong>Qwen3-ASR EN-JA&lt;/strong>（1.7B 参数），基于 Qwen3-ASR-1.7B 使用约 127 万个翻译对进行全参数 SFT 微调，EN→JA 评分 4.2/5，JA→EN 评分 4.0/5；(2) &lt;strong>Whisper EN-JA&lt;/strong>（756M 参数），从 Whisper large-v2 蒸馏而来，采用 4 层解码器，推理速度达 212 tok/s，是 Qwen3-ASR 的 4.6 倍。两个模型均在 FLEURS 测试集上与 OpenAI Whisper large-v3 和 Meta SeamlessM4T v2 Large 进行了对比评估。质量由 LLM 评审（Claude Opus 4.6）评分。各仓库独立进行评估，表格间的分数不可直接比较。&lt;/p></description></item><item><title>离线 TTS 基准测试：在 Android/iOS 上评测 18 个模型</title><link>https://voiceping.net/zh/blog/research-offline-tts-eval/</link><pubDate>Sun, 15 Feb 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-offline-tts-eval/</guid><description>&lt;p>&lt;strong>源代码：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/voiceping-ai/android-offline-tts-eval">android-offline-tts-eval&lt;/a>
 — 搭载 7 个模型的 Android TTS 基准测试应用（sherpa-onnx 和系统 TTS）&lt;/li>
&lt;li>&lt;a href="https://github.com/voiceping-ai/ios-offline-tts-eval">ios-offline-tts-eval&lt;/a>
 — 搭载 11 个模型的 iOS TTS 基准测试应用（含 AVSpeech）&lt;/li>
&lt;/ul>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们在 Android（7 个模型）和 iOS（11 个模型）上对 18 个端侧 TTS 模型进行了基准测试，覆盖 2 个推理引擎，测量合成速度（tok/s）、实时系数（RTF）和内存使用量。所有测试均使用英文文本提示。结果显示，Android System TTS 和 Piper VITS 合成速度最快（Android 上 33~42 tok/s），而 Kokoro 在两个平台上均未达到实时速度。iOS 上 Apple 内置的 AVSpeechSynthesizer 凭借极低的内存开销获得最高综合评分，但在开源模型中，Matcha + Vocos 在速度和资源效率之间提供了最佳平衡。本基准未进行正式的听感测试（MOS/ABX），仅测量速度和资源使用情况，不评估感知音质。&lt;/p>
&lt;h2 id="研究动机">研究动机&lt;/h2>
&lt;p>在移动和边缘应用中集成 TTS 的开发者面临三重权衡：合成延迟（能否跟上实时交互？）、内存占用（能否与 ASR 等其他 AI 模型在内存受限的设备上共存？）和音质（输出对于应用场景是否可接受？）。TTS 模型的速度从 440ms 的系统 TTS 到 15 秒的 Kokoro 相差 35 倍，内存则从 21MB 到 833MB 不等。&lt;/p></description></item><item><title>离线语音转写基准测试：在 Android/iOS/macOS/Windows 上评测 16 个模型</title><link>https://voiceping.net/zh/blog/research-offline-speech-transcription-benchmark/</link><pubDate>Sun, 15 Feb 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-offline-speech-transcription-benchmark/</guid><description>&lt;p>&lt;strong>源代码：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/voiceping-ai/android-offline-transcribe">android-offline-transcribe&lt;/a>
 — 搭载 16 个 ASR 模型和 6 个推理引擎的 Android 基准测试应用&lt;/li>
&lt;li>&lt;a href="https://github.com/voiceping-ai/ios-mac-offline-transcribe">ios-mac-offline-transcribe&lt;/a>
 — 搭载 17 个 ASR 模型和 9 个推理引擎的 iOS/macOS 基准测试应用&lt;/li>
&lt;li>&lt;a href="https://github.com/voiceping-ai/windows-offline-transcribe">windows-offline-transcribe&lt;/a>
 — 搭载 12 个 ASR 模型的 Windows 基准测试应用（仅 CPU）&lt;/li>
&lt;/ul>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们在 Android、iOS、macOS 和 Windows 全平台上对 16 个端侧语音识别模型进行了基准测试，覆盖 9 个推理引擎，测量推理速度（tok/s）、实时系数（RTF）和内存占用。本基准仅测量速度，不评估转写准确率（WER/CER）。主要发现：推理引擎的选择可使同一模型的性能差异达 51 倍（Android 上 sherpa-onnx vs whisper.cpp）；Moonshine Tiny 和 SenseVoice Small 在所有平台上实现最快推理；WhisperKit CoreML 在 4GB 的 iOS 设备上运行 Whisper Tiny 以上模型时会崩溃。所有基准测试应用和结果均已开源。&lt;/p>
&lt;h2 id="研究动机">研究动机&lt;/h2>
&lt;p>开发音频相关的边缘应用时，开发者面临组合选择难题：数十个 ASR 模型（从 31MB 的 Whisper Tiny 到 1.8GB 的 Qwen3 ASR）、多种推理引擎（ONNX Runtime、CoreML、whisper.cpp、MLX）以及 4 个以上目标平台——每种组合产生截然不同的速度和内存特征。已发布的模型基准通常是在服务器 GPU 上测试的结果，而非模型实际部署的消费级手机和笔记本电脑。&lt;/p></description></item><item><title>Whisper 生产实践：实时双语切换的踩坑经历与最终架构</title><link>https://voiceping.net/zh/blog/whisper-production-real-time-dual-language-switching/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/whisper-production-real-time-dual-language-switching/</guid><description>&lt;p>VoicePing 目前已在生产环境的会议中运行双语转录，支持日语、英语、普通话、粤语、韩语和越南语在句中自由切换。用户的期望很简单：无论语码转换多么频繁，语音识别和翻译都应无缝衔接。本文介绍我们如何设计了双语模式（Bilingual Mode）——基于定制化 Whisper V2 模型，在单条 WebSocket 流中实现自动、低延迟的语言切换。&lt;/p>
&lt;h2 id="目录">目录&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#1-%e5%8d%95%e8%af%ad%e5%9f%ba%e7%ba%bf">1. 单语基线&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#2-%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8f%8c%e8%af%ad%e6%a8%a1%e5%bc%8f%e6%98%af%e5%88%9a%e9%9c%80">2. 为什么&amp;quot;双语模式&amp;quot;是刚需&lt;/a>

&lt;ul>
&lt;li>&lt;a href="#%e6%bc%94%e7%a4%ba%e5%8f%8c%e8%af%ad%e6%a8%a1%e5%bc%8f%e5%ae%9e%e9%99%85%e6%95%88%e6%9e%9c">演示：双语模式实际效果&lt;/a>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#3-%e5%88%9d%e5%a7%8b%e6%96%b9%e6%a1%88%e5%a4%96%e9%83%a8%e8%af%ad%e8%a8%80%e6%a3%80%e6%b5%8b%e5%8f%8a%e5%85%b6%e5%a4%b1%e8%b4%a5%e5%8e%9f%e5%9b%a0">3. 初始方案：外部语言检测（及其失败原因）&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#4-%e7%aa%81%e7%a0%b4%e8%ae%a9-whisper-%e8%87%aa%e5%b7%b1%e5%91%8a%e8%af%89%e6%88%91%e4%bb%ac%e8%af%ad%e8%a8%80">4. 突破：让 Whisper 自己告诉我们语言&lt;/a>

&lt;ul>
&lt;li>&lt;a href="#41-whisper-%e5%8e%9f%e7%94%9f%e8%af%ad%e8%a8%80%e6%a3%80%e6%b5%8b">4.1 Whisper 原生语言检测&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#42-%e5%9f%ba%e4%ba%8e-whisper-%e5%8e%9f%e7%94%9f%e6%a3%80%e6%b5%8b%e7%9a%84%e6%9e%b6%e6%9e%84">4.2 基于 Whisper 原生检测的架构&lt;/a>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#5-%e7%a8%b3%e5%ae%9a%e8%af%ad%e7%a0%81%e8%bd%ac%e6%8d%a2%e8%be%b9%e7%95%8c">5. 稳定语码转换边界&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#6-%e9%80%9a%e7%94%a8%e5%a1%ab%e5%85%85%e8%a7%a3%e5%86%b3%e7%9f%ad%e9%9f%b3%e9%a2%91%e4%b8%8d%e7%a8%b3%e5%ae%9a%e9%97%ae%e9%a2%98">6. 通用填充解决短音频不稳定问题&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#7-%e8%bf%90%e8%90%a5%e7%ba%a6%e6%9d%9fgpumps-%e4%b8%8e%e5%b9%b6%e5%8f%91">7. 运营约束：GPU、MPS 与并发&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#8-%e6%80%bb%e7%bb%93">8. 总结&lt;/a>
&lt;/li>
&lt;li>&lt;a href="#%e5%8f%82%e8%80%83%e6%96%87%e7%8c%ae">参考文献&lt;/a>
&lt;/li>
&lt;/ul>
&lt;h2 id="1-单语基线">1. 单语基线&lt;/h2>
&lt;p>我们从传统的实时 ASR 架构出发：&lt;/p>
&lt;ol>
&lt;li>客户端流式传输 16 kHz PCM 音频。&lt;/li>
&lt;li>VAD 将音频切分为滑动窗口（可配置重叠，约 X 秒）。&lt;/li>
&lt;li>Whisper V2 派生模型以固定的 &lt;code>language=ja&lt;/code> 进行解码。&lt;/li>
&lt;li>后处理阶段对部分假设去重、文本修正，并通过 WebSocket 流式推送更新。&lt;/li>
&lt;/ol>
&lt;p>这一滑动窗口+拼接的流水线借鉴了 &amp;ldquo;Streaming Whisper: Enhanced Streaming Speech Recognition&amp;rdquo;（https://arxiv.org/abs/2307.14743）中描述的 Streaming Whisper 方法，为我们在叠加双语能力之前提供了稳定的基线。&lt;/p>
&lt;p>图 1：单语基线（单一固定语言）&lt;/p></description></item><item><title>说话人分离模型实战对比评估</title><link>https://voiceping.net/zh/blog/research-diarization-2025/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-diarization-2025/</guid><description>&lt;p>&lt;strong>测试配置&lt;/strong>：6 个场景，5 种语言（EN、JA、KO、VI、ZH），3 个模型
&lt;strong>硬件&lt;/strong>：NVIDIA GeForce RTX 4090
&lt;strong>日期&lt;/strong>：2025年12月&lt;/p>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们在 6 个场景中评估了 3 个说话人分离模型：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模型&lt;/th>
 &lt;th>说明&lt;/th>
 &lt;th>平均 DER&lt;/th>
 &lt;th>平均 RTF&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>NeMo Neural (MSDD)&lt;/td>
 &lt;td>带神经网络精炼的多尺度分离解码器&lt;/td>
 &lt;td>0.081&lt;/td>
 &lt;td>0.020&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>NeMo Clustering&lt;/td>
 &lt;td>不含 MSDD 的纯聚类方法&lt;/td>
 &lt;td>0.103&lt;/td>
 &lt;td>0.010&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Pyannote 3.1&lt;/td>
 &lt;td>端到端分离流水线&lt;/td>
 &lt;td>0.181&lt;/td>
 &lt;td>0.027&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>核心发现：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>NeMo Neural 兼具最佳准确度和快速处理能力&lt;/li>
&lt;li>日语在较长上下文中表现改善：30分钟以上音频性能提升&lt;/li>
&lt;li>不含日语的多语言处理表现优异（DER: 0.050）&lt;/li>
&lt;/ul>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>为了选择生产环境中使用的分离模型，我们设计了 6 个反映实际运行条件的测试场景：&lt;/p>
&lt;ul>
&lt;li>不同音频时长（10分钟至1小时）&lt;/li>
&lt;li>不同说话人数（4至14人）&lt;/li>
&lt;li>不同重叠程度（0%至40%）&lt;/li>
&lt;li>多语言音频混合&lt;/li>
&lt;/ul>
&lt;h2 id="2-测试模型">2. 测试模型&lt;/h2>
&lt;h3 id="nemo-neural-msdd">NeMo Neural (MSDD)&lt;/h3>
&lt;ul>
&lt;li>使用 TitaNet-large 生成 192 维说话人嵌入&lt;/li>
&lt;li>在 5 个时间尺度（1.0秒~3.0秒窗口）上处理音频&lt;/li>
&lt;li>MSDD 神经网络对初始聚类结果进行精炼&lt;/li>
&lt;li>平均 RTF：约 0.015~0.032&lt;/li>
&lt;/ul>
&lt;h3 id="nemo-clustering纯聚类">NeMo Clustering（纯聚类）&lt;/h3>
&lt;ul>
&lt;li>使用相同的嵌入模型（TitaNet-large）&lt;/li>
&lt;li>仅使用谱聚类，不含 MSDD 精炼&lt;/li>
&lt;li>跳过神经网络精炼，速度显著更快&lt;/li>
&lt;li>平均 RTF：约 0.014~0.028&lt;/li>
&lt;/ul>
&lt;h3 id="pyannote-31">Pyannote 3.1&lt;/h3>
&lt;ul>
&lt;li>包含 VAD、分割和聚类的端到端流水线&lt;/li>
&lt;li>使用 pyannote/segmentation-3.0 和 wespeaker 模型&lt;/li>
&lt;li>平均 RTF：约 0.018~0.043&lt;/li>
&lt;/ul>
&lt;h2 id="3-评估设置">3. 评估设置&lt;/h2>
&lt;h3 id="31-测试场景">3.1 测试场景&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>场景&lt;/th>
 &lt;th>时长&lt;/th>
 &lt;th>说话人数&lt;/th>
 &lt;th>重叠率&lt;/th>
 &lt;th>目的&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>长音频&lt;/td>
 &lt;td>10分钟&lt;/td>
 &lt;td>4~5&lt;/td>
 &lt;td>15%&lt;/td>
 &lt;td>标准生产场景&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>超长音频&lt;/td>
 &lt;td>30分钟&lt;/td>
 &lt;td>10~12&lt;/td>
 &lt;td>15%&lt;/td>
 &lt;td>压力测试&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>1小时音频&lt;/td>
 &lt;td>60分钟&lt;/td>
 &lt;td>12~14&lt;/td>
 &lt;td>15%&lt;/td>
 &lt;td>极限时长测试&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>高重叠&lt;/td>
 &lt;td>15分钟&lt;/td>
 &lt;td>8~10&lt;/td>
 &lt;td>40%&lt;/td>
 &lt;td>最差重叠场景&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多语言（5种）&lt;/td>
 &lt;td>15分钟&lt;/td>
 &lt;td>8&lt;/td>
 &lt;td>20%&lt;/td>
 &lt;td>EN+JA+KO+VI+ZH&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多语言（4种）&lt;/td>
 &lt;td>15分钟&lt;/td>
 &lt;td>8&lt;/td>
 &lt;td>20%&lt;/td>
 &lt;td>EN+KO+VI+ZH（无日语）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="32-评估指标">3.2 评估指标&lt;/h3>
&lt;p>&lt;strong>准确度指标：&lt;/strong>&lt;/p></description></item><item><title>通过 Go 重写将 WebSocket 代理效率提升 100 倍</title><link>https://voiceping.net/zh/blog/research-go-websocket-proxy/</link><pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-go-websocket-proxy/</guid><description>&lt;h2 id="概述">概述&lt;/h2>
&lt;p>我们将 WebSocket 代理服务器从 Python 重写为 Go，将 &lt;strong>CPU 使用率降低到 1/10&lt;/strong>，&lt;strong>内存消耗降低到 1/100&lt;/strong>。&lt;/p>
&lt;p>这个项目不仅提升了资源效率，还让我们学到了一个关于并发的重要经验：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>锁越小越好，越少越好。&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="背景">背景&lt;/h2>
&lt;p>VoicePing 的系统是一个实时 STT（语音识别）和翻译流水线。每个客户端设备将音频流式传输到后端，进行多语言的语音识别和翻译。&lt;/p>
&lt;p>WebSocket 代理服务器位于流水线的中间层：&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-go-websocket-proxy/go-websocket-arch.png"
 alt="系统架构概览"
 loading="lazy"
 decoding="async" width="1521" height="725">
&lt;/p>
&lt;ul>
&lt;li>每个客户端与 STT 代理维持一个持久的 WebSocket 会话&lt;/li>
&lt;li>代理将音频数据包转发到多个 GPU 推理服务器之一&lt;/li>
&lt;li>等待转录文本并以流式方式返回部分转录结果和翻译&lt;/li>
&lt;/ul>
&lt;p>该架构必须以亚秒级延迟处理&lt;strong>数千个并发实时音频会话&lt;/strong>。&lt;/p>
&lt;p>然而，我们之前基于 Python 的代理成为了瓶颈。&lt;/p>
&lt;h2 id="改进前python-代理低效">改进前：Python 代理（低效）&lt;/h2>
&lt;p>第一版代理服务器使用 Python（FastAPI + asyncio + websockets）实现，通过 Gunicorn 的多工作进程部署。&lt;/p>
&lt;p>在小规模下运行正常，但在生产流量下很快达到了资源上限：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>指标&lt;/th>
 &lt;th>Before (Python)&lt;/th>
 &lt;th>After (Go)&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>CPU 使用率&lt;/strong>&lt;/td>
 &lt;td>约 12 核 × 40~50%&lt;/td>
 &lt;td>约 12 核 × 4~5%&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>内存使用量&lt;/strong>&lt;/td>
 &lt;td>约 25 GB&lt;/td>
 &lt;td>约 10 MB&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="python-遇到瓶颈的原因">Python 遇到瓶颈的原因&lt;/h3>
&lt;p>尽管是异步模式，Python 的架构仍存在多个系统性瓶颈：&lt;/p></description></item><item><title>Part 2：扩展翻译推理：吞吐量 +82%</title><link>https://voiceping.net/zh/blog/research-translation-throughput/</link><pubDate>Sat, 15 Nov 2025 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-translation-throughput/</guid><description>&lt;h2 id="回顾问题所在">回顾：问题所在&lt;/h2>
&lt;p>在 &lt;a href="https://voiceping.net/zh/blog/research-translation-bottleneck/">Part 1&lt;/a>
 中，我们找到了瓶颈：FastAPI 服务使用多进程工作器和 IPC 队列来分发翻译任务，导致了以下问题：&lt;/p>
&lt;ul>
&lt;li>队列序列化开销&lt;/li>
&lt;li>工作进程间的 GPU 计算资源争用&lt;/li>
&lt;li>尖峰状 GPU 使用率&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>基线：25 个并发请求时 2.2 RPS&lt;/strong>&lt;/p>
&lt;p>改进方向：去掉多进程，利用 vLLM 的批量推理能力。&lt;/p>
&lt;hr>
&lt;h2 id="尝试-2静态批处理">尝试 2：静态批处理&lt;/h2>
&lt;p>在现有工作进程中实现了静态批处理。&lt;/p>
&lt;h3 id="实现">实现&lt;/h3>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 工作进程内&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>MAX_BATCH_SIZE &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">16&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BATCH_TIMEOUT &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0.05&lt;/span> &lt;span style="color:#75715e"># 50ms&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_keys &lt;span style="color:#f92672">=&lt;/span> []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_tasks &lt;span style="color:#f92672">=&lt;/span> []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 获取第一个任务（阻塞）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> first_key &lt;span style="color:#f92672">=&lt;/span> queue&lt;span style="color:#f92672">.&lt;/span>get()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_keys&lt;span style="color:#f92672">.&lt;/span>append(first_key)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_tasks&lt;span style="color:#f92672">.&lt;/span>append(tasks[first_key])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 尝试收集更多任务（带超时的非阻塞）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_start &lt;span style="color:#f92672">=&lt;/span> time&lt;span style="color:#f92672">.&lt;/span>time()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> len(batch_keys) &lt;span style="color:#f92672">&amp;lt;&lt;/span> MAX_BATCH_SIZE:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> time_remaining &lt;span style="color:#f92672">=&lt;/span> BATCH_TIMEOUT &lt;span style="color:#f92672">-&lt;/span> (time&lt;span style="color:#f92672">.&lt;/span>time() &lt;span style="color:#f92672">-&lt;/span> batch_start)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> time_remaining &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> key &lt;span style="color:#f92672">=&lt;/span> queue&lt;span style="color:#f92672">.&lt;/span>get(timeout&lt;span style="color:#f92672">=&lt;/span>time_remaining)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_keys&lt;span style="color:#f92672">.&lt;/span>append(key)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_tasks&lt;span style="color:#f92672">.&lt;/span>append(tasks[key])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> Empty:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 使用 vLLM 批量处理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> results &lt;span style="color:#f92672">=&lt;/span> translation_provider&lt;span style="color:#f92672">.&lt;/span>translate_batch(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> texts&lt;span style="color:#f92672">=&lt;/span>[t&lt;span style="color:#f92672">.&lt;/span>text &lt;span style="color:#66d9ef">for&lt;/span> t &lt;span style="color:#f92672">in&lt;/span> batch_tasks],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> source_langs&lt;span style="color:#f92672">=&lt;/span>[t&lt;span style="color:#f92672">.&lt;/span>source_lang &lt;span style="color:#66d9ef">for&lt;/span> t &lt;span style="color:#f92672">in&lt;/span> batch_tasks],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target_langs&lt;span style="color:#f92672">=&lt;/span>[t&lt;span style="color:#f92672">.&lt;/span>target_lang &lt;span style="color:#66d9ef">for&lt;/span> t &lt;span style="color:#f92672">in&lt;/span> batch_tasks]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>要点：&lt;/strong>&lt;/p></description></item><item><title>Part 1：翻译推理服务器扩展的瓶颈</title><link>https://voiceping.net/zh/blog/research-translation-bottleneck/</link><pubDate>Mon, 10 Nov 2025 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-translation-bottleneck/</guid><description>&lt;h2 id="问题">问题&lt;/h2>
&lt;p>我们使用 FastAPI 和 vLLM 运行翻译微服务。在高负载下，服务器出现了延迟问题，但 GPU 使用率指标无法解释这一现象。&lt;/p>
&lt;p>GPU 使用率呈现出不稳定的模式：急升至 93%，跌至 0%，再次急升。完全不是我们预期的持续高使用率。&lt;/p>
&lt;p>&lt;strong>核心问题：如果 GPU 存在空闲期，瓶颈究竟在哪里？&lt;/strong>&lt;/p>
&lt;p>本文介绍了我们如何在 FastAPI + 多进程架构中找到阻碍高效 GPU 利用的架构问题。&lt;/p>
&lt;hr>
&lt;h2 id="系统架构">系统架构&lt;/h2>
&lt;p>翻译服务以多台 API 服务器的形式在负载均衡器后运行。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-translation-bottleneck/translation-bottleneck-system-overview.svg"
 alt="图 1：包含客户端应用、代理/负载均衡器和多台 API 服务器的整体系统架构"
 loading="lazy"
 decoding="async">
&lt;/p>
&lt;ul>
&lt;li>&lt;strong>客户端&lt;/strong>：Web、移动端、后端服务&lt;/li>
&lt;li>&lt;strong>代理&lt;/strong>：根据语言对和服务器健康状态路由请求&lt;/li>
&lt;li>&lt;strong>API 服务器&lt;/strong>：多个 FastAPI 实例，每个运行 vLLM&lt;/li>
&lt;/ul>
&lt;p>本文重点关注单台 API 服务器的内部架构和瓶颈。&lt;/p>
&lt;h2 id="api-服务器架构">API 服务器架构&lt;/h2>
&lt;p>以下是一台 API 服务器的内部结构。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-translation-bottleneck/translation-bottleneck-api-architecture.svg"
 alt="图 2：包含 FastAPI、多进程队列、工作进程和 vLLM 实例的单台 API 服务器架构"
 loading="lazy"
 decoding="async">
&lt;/p>
&lt;h3 id="组件">组件&lt;/h3>
&lt;h4 id="1-fastapi-主进程">1. FastAPI 主进程&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 单线程异步事件循环&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@app.post&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;/translate&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">translate_endpoint&lt;/span>(request: TranslateRequest):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> result &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> translation_service&lt;span style="color:#f92672">.&lt;/span>translate(request)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> result
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>使用 async/await 处理 HTTP 请求&lt;/li>
&lt;li>单个 Python 进程，一个事件循环&lt;/li>
&lt;li>非阻塞 I/O 实现并发请求处理&lt;/li>
&lt;/ul>
&lt;h4 id="2-translationservice">2. TranslationService&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">TranslationService&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, worker: TranslationWorker):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>worker &lt;span style="color:#f92672">=&lt;/span> worker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">translate&lt;/span>(self, request: TranslateRequest) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> TranslateResponse:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 创建翻译任务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> event_task &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>worker&lt;span style="color:#f92672">.&lt;/span>add_translation_task(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> text&lt;span style="color:#f92672">=&lt;/span>request&lt;span style="color:#f92672">.&lt;/span>text,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> source_lang&lt;span style="color:#f92672">=&lt;/span>request&lt;span style="color:#f92672">.&lt;/span>source_lang,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target_lang&lt;span style="color:#f92672">=&lt;/span>request&lt;span style="color:#f92672">.&lt;/span>target_lang,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> timeout&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">30&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 异步等待结果&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> event_task&lt;span style="color:#f92672">.&lt;/span>event&lt;span style="color:#f92672">.&lt;/span>wait()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> TranslateResponse(translation&lt;span style="color:#f92672">=&lt;/span>event_task&lt;span style="color:#f92672">.&lt;/span>result&lt;span style="color:#f92672">.&lt;/span>translation)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>创建翻译任务&lt;/li>
&lt;li>管理带有 asyncio.Event 的 EventTask 对象&lt;/li>
&lt;li>在 async/await 和多进程之间架起桥梁&lt;/li>
&lt;/ul>
&lt;h4 id="3-translationworker主进程">3. TranslationWorker（主进程）&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">TranslationWorker&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>ctx &lt;span style="color:#f92672">=&lt;/span> multiprocessing&lt;span style="color:#f92672">.&lt;/span>get_context(&lt;span style="color:#e6db74">&amp;#34;spawn&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>translation_queue &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span> &lt;span style="color:#75715e"># 在 run() 中创建&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_queue &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_tasks: Dict[str, EventTask] &lt;span style="color:#f92672">=&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_initialize&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 在主进程中创建队列&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>translation_queue &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>ctx&lt;span style="color:#f92672">.&lt;/span>JoinableQueue(maxsize&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">300&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> manager &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>ctx&lt;span style="color:#f92672">.&lt;/span>Manager()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>translation_tasks &lt;span style="color:#f92672">=&lt;/span> manager&lt;span style="color:#f92672">.&lt;/span>dict() &lt;span style="color:#75715e"># 共享状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_queue &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>ctx&lt;span style="color:#f92672">.&lt;/span>Queue()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">add_translation_task&lt;/span>(&lt;span style="color:#f92672">...&lt;/span>) &lt;span style="color:#f92672">-&amp;gt;&lt;/span> EventTask:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> key &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;t_&amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> generate_random_key(&lt;span style="color:#ae81ff">10&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 存储到共享字典&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>translation_tasks[key] &lt;span style="color:#f92672">=&lt;/span> TranslationTask(&lt;span style="color:#f92672">...&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 通过队列发送给工作进程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>translation_queue&lt;span style="color:#f92672">.&lt;/span>put(key) &lt;span style="color:#75715e"># 序列化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 创建异步等待事件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> event_task &lt;span style="color:#f92672">=&lt;/span> EventTask(key)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_tasks[key] &lt;span style="color:#f92672">=&lt;/span> event_task
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> event_task
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>在主进程中创建队列（与工作进程共享）&lt;/li>
&lt;li>用于任务分发的 JoinableQueue&lt;/li>
&lt;li>用于共享任务状态的 manager().dict()&lt;/li>
&lt;li>用于结果返回的 Event queue&lt;/li>
&lt;/ul>
&lt;h4 id="4-工作进程">4. 工作进程&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">run&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> worker_id &lt;span style="color:#f92672">in&lt;/span> range(self&lt;span style="color:#f92672">.&lt;/span>num_workers):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> worker &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>ctx&lt;span style="color:#f92672">.&lt;/span>Process(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target&lt;span style="color:#f92672">=&lt;/span>self&lt;span style="color:#f92672">.&lt;/span>process_queue,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> args&lt;span style="color:#f92672">=&lt;/span>(worker_id, ready_event)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> worker&lt;span style="color:#f92672">.&lt;/span>start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">process_queue&lt;/span>(self, worker_id, ready_event):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 每个工作进程加载自己的 vLLM 实例&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> translation_processor &lt;span style="color:#f92672">=&lt;/span> TranslationProcessor(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> worker_id&lt;span style="color:#f92672">=&lt;/span>worker_id,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model_key&lt;span style="color:#f92672">=&lt;/span>self&lt;span style="color:#f92672">.&lt;/span>model_key,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gpu_memory_utilization&lt;span style="color:#f92672">=&lt;/span>self&lt;span style="color:#f92672">.&lt;/span>gpu_memory_per_worker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 从共享队列处理任务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> key &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>translation_queue&lt;span style="color:#f92672">.&lt;/span>get() &lt;span style="color:#75715e"># 反序列化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>translation_tasks[key]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 使用 vLLM 翻译&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> result &lt;span style="color:#f92672">=&lt;/span> translation_processor&lt;span style="color:#f92672">.&lt;/span>translate(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task&lt;span style="color:#f92672">.&lt;/span>text,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task&lt;span style="color:#f92672">.&lt;/span>source_lang,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task&lt;span style="color:#f92672">.&lt;/span>target_lang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 返回结果&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_queue&lt;span style="color:#f92672">.&lt;/span>put((key, EventType&lt;span style="color:#f92672">.&lt;/span>completed, result)) &lt;span style="color:#75715e"># 序列化&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>作为独立进程启动（ctx.Process）&lt;/li>
&lt;li>每个工作进程加载自己的 vLLM 模型实例&lt;/li>
&lt;li>从共享 translation_queue 中拉取任务&lt;/li>
&lt;li>通过共享 event_queue 返回结果&lt;/li>
&lt;/ul>
&lt;h4 id="5-eventtask异步同步机制">5. EventTask（异步同步机制）&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">EventTask&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, key: str):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>key &lt;span style="color:#f92672">=&lt;/span> key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event &lt;span style="color:#f92672">=&lt;/span> asyncio&lt;span style="color:#f92672">.&lt;/span>Event() &lt;span style="color:#75715e"># 异步同步&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_type &lt;span style="color:#f92672">=&lt;/span> EventType&lt;span style="color:#f92672">.&lt;/span>waiting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>result &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">update&lt;/span>(self, event_type, result):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event_type &lt;span style="color:#f92672">=&lt;/span> event_type
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>result &lt;span style="color:#f92672">=&lt;/span> result
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>event&lt;span style="color:#f92672">.&lt;/span>set() &lt;span style="color:#75715e"># 唤醒等待中的协程&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>在多进程和 async/await 之间架起桥梁&lt;/li>
&lt;li>为每个请求分配 EventTask&lt;/li>
&lt;li>&lt;code>await event.wait()&lt;/code> 阻塞协程直到工作进程完成&lt;/li>
&lt;/ul>
&lt;h2 id="请求流程">请求流程&lt;/h2>
&lt;p>以下是单个翻译请求的完整处理流程。&lt;/p></description></item><item><title>构建面向大规模数据采集的可扩展异步 Web 爬虫</title><link>https://voiceping.net/zh/blog/research-web-crawler/</link><pubDate>Sun, 15 Sep 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-web-crawler/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本项目开发了一个可扩展的异步 Web 爬虫，用于高效的大规模数据采集。系统基于 Python 的 asyncio、aiohttp 和 BeautifulSoup 构建，能够在遵守 robots.txt、处理 JavaScript 渲染内容以及控制请求频率的同时完成网站爬取。该爬虫成功处理了超过 110 万个内部 URL 和 1900 万个外部引用链接。&lt;/p>
&lt;p>&lt;strong>核心特性：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>异步并发请求处理&lt;/li>
&lt;li>robots.txt 合规与速率限制&lt;/li>
&lt;li>通过 Playwright 支持 JavaScript 渲染&lt;/li>
&lt;li>重复 URL 检测与过滤&lt;/li>
&lt;li>错误处理与重试机制&lt;/li>
&lt;li>基于 SQLite 的数据持久化&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>Web 爬虫是现代数据采集的基础技术，为搜索引擎、数据分析和机器学习流水线提供数据支撑。本项目实现了一个可在生产环境使用的 Web 爬虫，在速度与合规爬取之间取得了良好的平衡。&lt;/p>
&lt;h3 id="为什么选择异步爬取">为什么选择异步爬取？&lt;/h3>
&lt;p>传统的同步爬虫每次只能处理一个 URL，导致 CPU 和网络利用率低下。基于 Python asyncio 的异步爬取具有以下优势：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>并发性&lt;/strong>：同时处理多个 URL&lt;/li>
&lt;li>&lt;strong>资源效率&lt;/strong>：非阻塞 I/O 操作&lt;/li>
&lt;li>&lt;strong>可扩展性&lt;/strong>：支持数千个并发连接&lt;/li>
&lt;li>&lt;strong>速度&lt;/strong>：显著缩短爬取时间&lt;/li>
&lt;/ul>
&lt;h3 id="项目目标">项目目标&lt;/h3>
&lt;ol>
&lt;li>构建遵守网站策略（robots.txt）的爬虫&lt;/li>
&lt;li>处理静态内容和 JavaScript 渲染内容&lt;/li>
&lt;li>实现健壮的错误处理和重试逻辑&lt;/li>
&lt;li>高效存储和去重爬取数据&lt;/li>
&lt;li>在保持礼貌访问的同时实现高吞吐量&lt;/li>
&lt;/ol>
&lt;h2 id="2-方法论">2. 方法论&lt;/h2>
&lt;h3 id="21-系统架构">2.1 系统架构&lt;/h3>
&lt;p>爬虫由五个主要组件构成：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>组件&lt;/th>
 &lt;th>技术&lt;/th>
 &lt;th>用途&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>HTTP 客户端&lt;/strong>&lt;/td>
 &lt;td>aiohttp&lt;/td>
 &lt;td>异步 HTTP 请求处理&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>HTML 解析器&lt;/strong>&lt;/td>
 &lt;td>BeautifulSoup4&lt;/td>
 &lt;td>提取链接和内容&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>JS 渲染器&lt;/strong>&lt;/td>
 &lt;td>Playwright&lt;/td>
 &lt;td>处理动态内容&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>数据库&lt;/strong>&lt;/td>
 &lt;td>SQLite&lt;/td>
 &lt;td>存储已爬取的 URL 和元数据&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>队列管理器&lt;/strong>&lt;/td>
 &lt;td>asyncio.Queue&lt;/td>
 &lt;td>管理爬取队列&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="22-核心实现">2.2 核心实现&lt;/h3>
&lt;h4 id="异步请求处理器">异步请求处理器&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> aiohttp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> asyncio
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> bs4 &lt;span style="color:#f92672">import&lt;/span> BeautifulSoup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> urllib.parse &lt;span style="color:#f92672">import&lt;/span> urljoin, urlparse
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AsyncCrawler&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, max_concurrent&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">100&lt;/span>, delay&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1.0&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>max_concurrent &lt;span style="color:#f92672">=&lt;/span> max_concurrent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>delay &lt;span style="color:#f92672">=&lt;/span> delay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>session &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>visited &lt;span style="color:#f92672">=&lt;/span> set()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>queue &lt;span style="color:#f92672">=&lt;/span> asyncio&lt;span style="color:#f92672">.&lt;/span>Queue()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">fetch&lt;/span>(self, url):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;Fetch a single URL asynchronously&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">with&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>session&lt;span style="color:#f92672">.&lt;/span>get(url, timeout&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>) &lt;span style="color:#66d9ef">as&lt;/span> response:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> response&lt;span style="color:#f92672">.&lt;/span>status &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">200&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> response&lt;span style="color:#f92672">.&lt;/span>text()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Error &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>response&lt;span style="color:#f92672">.&lt;/span>status&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> asyncio&lt;span style="color:#f92672">.&lt;/span>TimeoutError:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Timeout: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">except&lt;/span> &lt;span style="color:#a6e22e">Exception&lt;/span> &lt;span style="color:#66d9ef">as&lt;/span> e:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Error fetching &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>url&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>e&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">parse&lt;/span>(self, html, base_url):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;Extract all links from HTML&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> soup &lt;span style="color:#f92672">=&lt;/span> BeautifulSoup(html, &lt;span style="color:#e6db74">&amp;#39;html.parser&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> links &lt;span style="color:#f92672">=&lt;/span> []
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> link &lt;span style="color:#f92672">in&lt;/span> soup&lt;span style="color:#f92672">.&lt;/span>find_all(&lt;span style="color:#e6db74">&amp;#39;a&amp;#39;&lt;/span>, href&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> href &lt;span style="color:#f92672">=&lt;/span> link[&lt;span style="color:#e6db74">&amp;#39;href&amp;#39;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> absolute_url &lt;span style="color:#f92672">=&lt;/span> urljoin(base_url, href)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> links&lt;span style="color:#f92672">.&lt;/span>append(absolute_url)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> links
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="robotstxt-合规">robots.txt 合规&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> urllib.robotparser &lt;span style="color:#f92672">import&lt;/span> RobotFileParser
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">RobotsChecker&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>parsers &lt;span style="color:#f92672">=&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">can_fetch&lt;/span>(self, url, user_agent&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;*&amp;#39;&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;Check if URL can be crawled per robots.txt&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> parsed &lt;span style="color:#f92672">=&lt;/span> urlparse(url)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> robots_url &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>parsed&lt;span style="color:#f92672">.&lt;/span>scheme&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">://&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>parsed&lt;span style="color:#f92672">.&lt;/span>netloc&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/robots.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> robots_url &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#f92672">in&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>parsers:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> parser &lt;span style="color:#f92672">=&lt;/span> RobotFileParser()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> parser&lt;span style="color:#f92672">.&lt;/span>set_url(robots_url)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> parser&lt;span style="color:#f92672">.&lt;/span>read()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>parsers[robots_url] &lt;span style="color:#f92672">=&lt;/span> parser
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">except&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># If robots.txt doesn&amp;#39;t exist, allow crawling&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>parsers[robots_url]&lt;span style="color:#f92672">.&lt;/span>can_fetch(user_agent, url)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="速率限制">速率限制&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> time
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">RateLimiter&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, requests_per_second&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>delay &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span> &lt;span style="color:#f92672">/&lt;/span> requests_per_second
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>last_request &lt;span style="color:#f92672">=&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">wait&lt;/span>(self, domain):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;Enforce rate limit per domain&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> now &lt;span style="color:#f92672">=&lt;/span> time&lt;span style="color:#f92672">.&lt;/span>time()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> domain &lt;span style="color:#f92672">in&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>last_request:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> elapsed &lt;span style="color:#f92672">=&lt;/span> now &lt;span style="color:#f92672">-&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>last_request[domain]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> elapsed &lt;span style="color:#f92672">&amp;lt;&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>delay:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> asyncio&lt;span style="color:#f92672">.&lt;/span>sleep(self&lt;span style="color:#f92672">.&lt;/span>delay &lt;span style="color:#f92672">-&lt;/span> elapsed)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>last_request[domain] &lt;span style="color:#f92672">=&lt;/span> time&lt;span style="color:#f92672">.&lt;/span>time()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="23-javascript-渲染">2.3 JavaScript 渲染&lt;/h3>
&lt;p>对于大量使用 JavaScript 的网站，我们采用 Playwright 进行渲染：&lt;/p></description></item><item><title>面向人脸与情绪识别的视频和音频数据预处理与分析</title><link>https://voiceping.net/zh/blog/research-face-emotion/</link><pubDate>Sun, 15 Sep 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-face-emotion/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本项目构建了一个自动化流水线，用于预处理视频和音频数据，为视频生成模型的训练提取关键信息。该流水线涵盖人脸检测、情绪分类、姿态估计和音频处理。&lt;/p>
&lt;p>&lt;strong>核心功能：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>自动检测和分离唯一人脸&lt;/li>
&lt;li>头部姿态估计（yaw、pitch、roll）&lt;/li>
&lt;li>基于深度学习的情绪分类&lt;/li>
&lt;li>音频分类与语音分离&lt;/li>
&lt;li>片段生成（3~10 秒）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>随着基于视频的生成模型快速发展，经过良好预处理的视频数据集需求日益增长。本项目自动化了以下视频和音频数据的预处理工作：&lt;/p>
&lt;ul>
&lt;li>自动分类和识别唯一人脸&lt;/li>
&lt;li>沿时间轴检测面部情绪和头部姿态&lt;/li>
&lt;li>对背景音乐进行音频分类并分离语音&lt;/li>
&lt;li>裁剪和精炼视频，以供生成模型使用&lt;/li>
&lt;/ul>
&lt;h2 id="2-方法">2. 方法&lt;/h2>
&lt;h3 id="流水线概述">流水线概述&lt;/h3>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-face-emotion/face-emotion-pipeline.png"
 alt="视频预处理流水线工作流程"
 loading="lazy"
 decoding="async" width="1544" height="1396">
&lt;/p>
&lt;p>预处理流水线由五个主要阶段组成：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>阶段&lt;/th>
 &lt;th>功能&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>音频分类&lt;/strong>&lt;/td>
 &lt;td>识别语音并从背景噪声中分离&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>人脸检测&lt;/strong>&lt;/td>
 &lt;td>检测和识别视频中的唯一人脸&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>人脸裁剪&lt;/strong>&lt;/td>
 &lt;td>生成以人脸为中心的片段（3~10 秒）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>姿态估计&lt;/strong>&lt;/td>
 &lt;td>估计头部方向（yaw、pitch、roll）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>情绪分类&lt;/strong>&lt;/td>
 &lt;td>在每一帧中检测情绪&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="21-视频处理">2.1 视频处理&lt;/h3>
&lt;p>使用 yt-dlp 下载视频，逐帧处理：&lt;/p>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">download_video&lt;/span>(url, output_dir):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ydl_opts &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;format&amp;#39;&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;best&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;outtmpl&amp;#39;&lt;/span>: os&lt;span style="color:#f92672">.&lt;/span>path&lt;span style="color:#f92672">.&lt;/span>join(output_dir, &lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">%(title)s&lt;/span>&lt;span style="color:#e6db74">-&lt;/span>&lt;span style="color:#e6db74">%(id)s&lt;/span>&lt;span style="color:#e6db74">.&lt;/span>&lt;span style="color:#e6db74">%(ext)s&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">with&lt;/span> yt_dlp&lt;span style="color:#f92672">.&lt;/span>YoutubeDL(ydl_opts) &lt;span style="color:#66d9ef">as&lt;/span> ydl:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ydl&lt;span style="color:#f92672">.&lt;/span>download([url])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="22-音频分类">2.2 音频分类&lt;/h3>
&lt;p>使用 &lt;strong>Audio Spectrogram Transformer&lt;/strong> 模型对音频进行分类：&lt;/p></description></item><item><title>大语言模型机器翻译与幻觉问题的缓解</title><link>https://voiceping.net/zh/blog/research-mt-hallucination/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-mt-hallucination/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>大语言模型（LLM）在自然语言处理任务中展现出卓越的性能。本研究探索了对 Llama 3.1 进行中译英机器翻译的微调，并通过训练和解码策略来应对幻觉问题。&lt;/p>
&lt;p>&lt;strong>主要成果：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>微调模型在文档级数据上达到 &lt;strong>BLEU 40.8&lt;/strong>（基线 &lt;strong>19.6&lt;/strong>）&lt;/li>
&lt;li>&lt;strong>COMET 0.891&lt;/strong>（基线 &lt;strong>0.820&lt;/strong>）&lt;/li>
&lt;li>成功缓解长上下文翻译中的幻觉现象&lt;/li>
&lt;li>在提升文档级性能的同时保持了句子级质量&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-背景">1. 背景&lt;/h2>
&lt;h3 id="大语言模型">大语言模型&lt;/h3>
&lt;p>以 Llama 为代表的 LLM 正在革新自然语言处理领域，在理解和生成类人文本方面展现出非凡的能力。由于能够针对特定任务进行微调，LLM 非常适合用于提升机器翻译水平。&lt;/p>
&lt;h3 id="参数高效微调lora">参数高效微调（LoRA）&lt;/h3>
&lt;p>LoRA（Low-Rank Adaptation）能够在不更新全部模型参数的情况下实现微调：&lt;/p>
&lt;ul>
&lt;li>冻结预训练模型参数&lt;/li>
&lt;li>插入可训练的低秩矩阵&lt;/li>
&lt;li>大幅降低训练成本和时间&lt;/li>
&lt;/ul>
&lt;h3 id="神经机器翻译与幻觉">神经机器翻译与幻觉&lt;/h3>
&lt;p>NMT 中的幻觉是指不忠实、虚构或无意义的输出内容：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>类型&lt;/th>
 &lt;th>说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>内在幻觉&lt;/strong>&lt;/td>
 &lt;td>输出包含与原文不符的错误信息&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>外在幻觉&lt;/strong>&lt;/td>
 &lt;td>模型生成与原文无关的额外内容&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>扰动幻觉&lt;/strong>&lt;/td>
 &lt;td>输入轻微变化导致输出截然不同&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>自然幻觉&lt;/strong>&lt;/td>
 &lt;td>源于训练数据集中的噪声&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="解码策略">解码策略&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方法&lt;/th>
 &lt;th>说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>贪心搜索&lt;/strong>&lt;/td>
 &lt;td>每步选择概率最高的 token&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>束搜索&lt;/strong>&lt;/td>
 &lt;td>同时考虑概率最高的 N 个序列&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>温度采样&lt;/strong>&lt;/td>
 &lt;td>调整概率分布的锐度&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Top-p 采样&lt;/strong>&lt;/td>
 &lt;td>从累积概率超过阈值的 token 中采样&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Top-k 采样&lt;/strong>&lt;/td>
 &lt;td>从概率最高的 k 个 token 中采样&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="2-实验">2. 实验&lt;/h2>
&lt;h3 id="数据集">数据集&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>数据集&lt;/th>
 &lt;th>文档数&lt;/th>
 &lt;th>句子数&lt;/th>
 &lt;th>词数（源/目标）&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>NewsCommentary-v18.1&lt;/td>
 &lt;td>11,147&lt;/td>
 &lt;td>443,677&lt;/td>
 &lt;td>1,640万/970万&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Ted Talks&lt;/td>
 &lt;td>22&lt;/td>
 &lt;td>1,949&lt;/td>
 &lt;td>5.1万/3.2万&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="评估指标">评估指标&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>BLEU&lt;/strong>：Bilingual Evaluation Understudy — 将译文 n-gram 与参考译文进行比较&lt;/li>
&lt;li>&lt;strong>COMET&lt;/strong>：与人工评判相关性最高的神经网络评估框架&lt;/li>
&lt;/ul>
&lt;h3 id="实验环境">实验环境&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>模型&lt;/strong>：Llama 3.1 8B Instruct&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>：NVIDIA A100（80GB）&lt;/li>
&lt;li>&lt;strong>框架&lt;/strong>：Unsloth 加速训练&lt;/li>
&lt;/ul>
&lt;h3 id="微调配置">微调配置&lt;/h3>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>model &lt;span style="color:#f92672">=&lt;/span> FastLanguageModel&lt;span style="color:#f92672">.&lt;/span>from_pretrained(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model_name&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;unsloth/Meta-Llama-3.1-8B-Instruct&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> max_seq_length&lt;span style="color:#f92672">=&lt;/span>max_seq_length,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dtype&lt;span style="color:#f92672">=&lt;/span>dtype,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> load_in_4bit&lt;span style="color:#f92672">=&lt;/span>load_in_4bit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>model &lt;span style="color:#f92672">=&lt;/span> FastLanguageModel&lt;span style="color:#f92672">.&lt;/span>get_peft_model(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> r&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>, &lt;span style="color:#75715e"># LoRA rank&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target_modules&lt;span style="color:#f92672">=&lt;/span>[&lt;span style="color:#e6db74">&amp;#34;q_proj&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;k_proj&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;v_proj&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;o_proj&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;gate_proj&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;up_proj&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;down_proj&amp;#34;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> lora_alpha&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> use_gradient_checkpointing&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;unsloth&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="3-结果">3. 结果&lt;/h2>
&lt;h3 id="分布内性能文档级">分布内性能（文档级）&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>训练样本数&lt;/th>
 &lt;th>BLEU&lt;/th>
 &lt;th>COMET&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>10&lt;/td>
 &lt;td>35.8&lt;/td>
 &lt;td>0.885&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>100&lt;/td>
 &lt;td>36.9&lt;/td>
 &lt;td>0.889&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>1,000&lt;/td>
 &lt;td>39.7&lt;/td>
 &lt;td>0.890&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>10,000&lt;/td>
 &lt;td>40.8&lt;/td>
 &lt;td>0.891&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>基线&lt;/strong>&lt;/td>
 &lt;td>&lt;strong>19.6&lt;/strong>&lt;/td>
 &lt;td>&lt;strong>0.820&lt;/strong>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>要点：&lt;/strong> 微调使文档级翻译的 BLEU 相比基线提升了 100% 以上。&lt;/p></description></item><item><title>使用 Bert-VITS2 构建中文（普通话）语音合成系统</title><link>https://voiceping.net/zh/blog/research-bert-vits2-tts/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-bert-vits2-tts/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本研究介绍了使用 Bert-VITS2 框架开发快速且自然的普通话语音合成（TTS）系统的工作。该系统专为会议场景设计，旨在生成清晰、富有表现力且符合语境的语音。&lt;/p>
&lt;p>&lt;strong>核心成果：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在对比模型中取得最低 &lt;strong>WER 0.27&lt;/strong>&lt;/li>
&lt;li>语音自然度 &lt;strong>MOS 2.90&lt;/strong>&lt;/li>
&lt;li>成功合成最长 22 秒的语音&lt;/li>
&lt;li>基于 AISHELL-3 数据集训练（85小时，218名说话人）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;h3 id="什么是语音合成">什么是语音合成&lt;/h3>
&lt;p>语音合成（TTS）技术将书面文字转换为自然流畅的语音。现代 TTS 系统借助深度学习生成越来越自然、富有表现力的语音，应用领域包括：&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-bert-vits2-tts/bert-vits2-01.png"
 alt="语音合成概述"
 loading="lazy"
 decoding="async" width="700" height="378">
&lt;/p>
&lt;ul>
&lt;li>智能助手&lt;/li>
&lt;li>无障碍阅读方案&lt;/li>
&lt;li>导航系统&lt;/li>
&lt;li>自动化客户服务&lt;/li>
&lt;/ul>
&lt;h3 id="为什么选择中文">为什么选择中文&lt;/h3>
&lt;p>普通话是全球使用人数最多的语言，拥有超过十亿使用者。然而，由于其声调特性和复杂的语言结构，普通话为 TTS 带来了独特的挑战。&lt;/p>
&lt;h3 id="什么是-bert-vits2">什么是 Bert-VITS2&lt;/h3>
&lt;p>Bert-VITS2 将预训练语言模型与先进的语音合成技术相结合：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>BERT 集成&lt;/strong>：深度理解语义和上下文细微差异&lt;/li>
&lt;li>&lt;strong>GAN 风格训练&lt;/strong>：通过对抗学习生成高度逼真的语音&lt;/li>
&lt;li>&lt;strong>基于 VITS2&lt;/strong>：最先进的语音合成架构&lt;/li>
&lt;/ul>
&lt;h2 id="2-方法">2. 方法&lt;/h2>
&lt;h3 id="21-数据集选择">2.1 数据集选择&lt;/h3>
&lt;p>本研究选用了 &lt;strong>AISHELL-3&lt;/strong> 数据集：&lt;/p>
&lt;ul>
&lt;li>85 小时音频数据&lt;/li>
&lt;li>218 名说话人&lt;/li>
&lt;li>每位说话人平均约 30 分钟&lt;/li>
&lt;li>高质量转录文本&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>注意：&lt;/strong> 最初使用 Alimeeting（118.75 小时）进行实验，但由于转录质量不佳和每位说话人音频时长不足，生成了空白音频。&lt;/p>&lt;/blockquote>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-bert-vits2-tts/bert-vits2-02.png"
 alt="数据预处理 WebUI 界面"
 loading="lazy"
 decoding="async" width="2048" height="972">
&lt;/p>
&lt;h3 id="22-模型架构">2.2 模型架构&lt;/h3>
&lt;p>Bert-VITS2 框架由四个主要组件构成：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>组件&lt;/th>
 &lt;th>功能&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>TextEncoder&lt;/strong>&lt;/td>
 &lt;td>使用预训练 BERT 处理输入文本以理解语义&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>DurationPredictor&lt;/strong>&lt;/td>
 &lt;td>带有随机变化的音素时长估计&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Flow&lt;/strong>&lt;/td>
 &lt;td>使用归一化流对音高和能量建模&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Decoder&lt;/strong>&lt;/td>
 &lt;td>合成最终语音波形&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="23-训练过程">2.3 训练过程&lt;/h3>
&lt;h4 id="损失函数">损失函数&lt;/h4>
&lt;ul>
&lt;li>&lt;strong>重建损失&lt;/strong>：使生成语音匹配真实语音&lt;/li>
&lt;li>&lt;strong>时长损失&lt;/strong>：最小化音素时长预测误差&lt;/li>
&lt;li>&lt;strong>对抗损失&lt;/strong>：促进生成逼真语音&lt;/li>
&lt;li>&lt;strong>特征匹配损失&lt;/strong>：对齐中间层特征&lt;/li>
&lt;/ul>
&lt;h4 id="模式崩溃缓解">模式崩溃缓解&lt;/h4>
&lt;ul>
&lt;li>用于稳定判别器的 Gradient Penalty&lt;/li>
&lt;li>生成器和判别器的 Spectral Normalization&lt;/li>
&lt;li>逐步增加复杂度的渐进式训练&lt;/li>
&lt;/ul>
&lt;h4 id="超参数">超参数&lt;/h4>
&lt;div class="highlight">&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;">&lt;tr>&lt;td style="vertical-align:top;padding:0;margin:0;border:0;">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
&lt;/span>&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;train&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;batch_size&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">20&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;learning_rate&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">0.00001&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;epochs&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">100&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;bf16_run&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;data&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;sampling_rate&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">44100&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;n_speakers&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">174&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>提示：&lt;/strong> 训练在单张 RTX 4090 GPU 上使用 bfloat16 精度进行。&lt;/p></description></item><item><title>使用 RAFT（检索增强微调）提升英中翻译性能</title><link>https://voiceping.net/zh/blog/research-raft-translation/</link><pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-raft-translation/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本研究探索使用 RAFT（Retrieval-Augmented Fine-Tuning：检索增强微调）来提升 Llama 3.1-8B 的英中双向翻译能力。RAFT 将检索机制与微调相结合，在训练过程中提供上下文示例。&lt;/p>
&lt;p>&lt;strong>主要发现：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>基准微调在整体上取得了最佳结果&lt;/li>
&lt;li>RAFT 在特定指标上显示出小幅改进&lt;/li>
&lt;li>随机 RAFT 在某些情况下优于基于相似度的 RAFT&lt;/li>
&lt;li>翻译质量高度依赖训练数据的相关性&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>大语言模型擅长语言任务，但可以通过领域特定的优化进一步提升性能。本研究探索 RAFT——一种在训练时用检索到的示例进行增强的技术——能否提高翻译质量。&lt;/p>
&lt;h3 id="研究问题">研究问题&lt;/h3>
&lt;ol>
&lt;li>RAFT 能否相比标准微调改进翻译效果？&lt;/li>
&lt;li>基于相似度的检索是否优于随机检索？&lt;/li>
&lt;li>不同的 RAFT 配置如何影响双向翻译？&lt;/li>
&lt;/ol>
&lt;h2 id="2-方法">2. 方法&lt;/h2>
&lt;h3 id="raft-概述">RAFT 概述&lt;/h3>
&lt;p>RAFT（Retrieval-Augmented Fine-Tuning）通过以下方式增强训练过程：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>检索&lt;/strong>：为每个训练样本从语料库中检索相关示例&lt;/li>
&lt;li>&lt;strong>增强&lt;/strong>：用检索到的示例丰富训练上下文&lt;/li>
&lt;li>&lt;strong>微调&lt;/strong>：在这一丰富的上下文中对模型进行微调&lt;/li>
&lt;/ol>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-raft-translation/raft-diagram.png"
 alt="RAFT 方法示意图"
 loading="lazy"
 decoding="async" width="1298" height="302">
&lt;/p>
&lt;h3 id="实验设置">实验设置&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>组件&lt;/th>
 &lt;th>配置&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>基础模型&lt;/strong>&lt;/td>
 &lt;td>Llama 3.1-8B Instruct&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>微调方法&lt;/strong>&lt;/td>
 &lt;td>LoRA (r=16, alpha=16)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>数据集&lt;/strong>&lt;/td>
 &lt;td>News Commentary v18.1 (zh-en)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>GPU&lt;/strong>&lt;/td>
 &lt;td>NVIDIA A100 80GB&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="数据集准备">数据集准备&lt;/h3>
&lt;p>News Commentary 数据集包含英中平行句对：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>训练集&lt;/strong>：10,000 个句对&lt;/li>
&lt;li>&lt;strong>评估集&lt;/strong>：TED Talks 语料&lt;/li>
&lt;li>经过预处理以确保质量和长度的一致性&lt;/li>
&lt;/ul>
&lt;h3 id="raft-配置">RAFT 配置&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>配置&lt;/th>
 &lt;th>说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>基准&lt;/strong>&lt;/td>
 &lt;td>不使用检索的标准微调&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>相似度 RAFT&lt;/strong>&lt;/td>
 &lt;td>使用嵌入向量检索 top-k 相似示例&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>随机 RAFT&lt;/strong>&lt;/td>
 &lt;td>从语料库中随机采样 k 个示例&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="3-结果">3. 结果&lt;/h2>
&lt;h3 id="英语--中文翻译">英语 → 中文翻译&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方法&lt;/th>
 &lt;th>BLEU&lt;/th>
 &lt;th>COMET&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>基线（未微调）&lt;/td>
 &lt;td>15.2&lt;/td>
 &lt;td>0.785&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>基准微调&lt;/td>
 &lt;td>&lt;strong>28.4&lt;/strong>&lt;/td>
 &lt;td>&lt;strong>0.856&lt;/strong>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>相似度 RAFT (k=3)&lt;/td>
 &lt;td>27.1&lt;/td>
 &lt;td>0.849&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>随机 RAFT (k=3)&lt;/td>
 &lt;td>27.8&lt;/td>
 &lt;td>0.852&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="中文--英语翻译">中文 → 英语翻译&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方法&lt;/th>
 &lt;th>BLEU&lt;/th>
 &lt;th>COMET&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>基线（未微调）&lt;/td>
 &lt;td>18.7&lt;/td>
 &lt;td>0.812&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>基准微调&lt;/td>
 &lt;td>&lt;strong>31.2&lt;/strong>&lt;/td>
 &lt;td>&lt;strong>0.871&lt;/strong>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>相似度 RAFT (k=3)&lt;/td>
 &lt;td>30.5&lt;/td>
 &lt;td>0.865&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>随机 RAFT (k=3)&lt;/td>
 &lt;td>30.9&lt;/td>
 &lt;td>0.868&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>注意：&lt;/strong> 在本实验中，基准微调始终优于 RAFT 配置。这可能是由于 News Commentary 数据集的同质性特点所致。&lt;/p></description></item><item><title>说话人分离性能评估：Pyannote.audio vs Nvidia NeMo 及 GPT-4 后处理</title><link>https://voiceping.net/zh/blog/research-speaker-diarization/</link><pubDate>Mon, 15 Apr 2024 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-speaker-diarization/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>本文评估并比较了两个先进的开源说话人分离框架：&lt;strong>Pyannote.audio&lt;/strong> 和 &lt;strong>Nvidia NeMo&lt;/strong>。评估重点关注不同音频场景下的 Diarization Error Rate（DER）、执行时间和 GPU 资源使用情况。此外，还探索了使用 OpenAI GPT-4-Turbo 进行后处理以提高分离准确率的方法。&lt;/p>
&lt;p>&lt;strong>主要结果：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Nvidia NeMo 在 2 人说话人场景中 DER 低约 9%&lt;/li>
&lt;li>Pyannote.audio 在多说话人（9人以上）场景中表现更优&lt;/li>
&lt;li>GPT-4-Turbo 后处理展现出潜力，但需要集成音频上下文&lt;/li>
&lt;li>展示了实时说话人分离 Web 应用&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;h3 id="什么是说话人分离">什么是说话人分离？&lt;/h3>
&lt;p>说话人分离是根据不同的说话人对音频进行分段和标注的过程，回答&amp;quot;谁在什么时候说了什么&amp;quot;这一问题。它与自动语音识别（ASR）结合使用，是对话分析的关键工具。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-speaker-diarization/sd-pipeline.png"
 alt="说话人分离流程"
 loading="lazy"
 decoding="async" width="128" height="128">
&lt;/p>
&lt;p>说话人分离系统由以下部分组成：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>语音活动检测（VAD）&lt;/strong> - 识别语音出现的时间戳&lt;/li>
&lt;li>&lt;strong>音频嵌入模型&lt;/strong> - 从带时间戳的片段中提取嵌入向量&lt;/li>
&lt;li>&lt;strong>聚类&lt;/strong> - 对嵌入向量进行分组以估计说话人数量&lt;/li>
&lt;/ol>
&lt;h3 id="pyannoteaudio">Pyannote.audio&lt;/h3>
&lt;p>Pyannote.audio 是基于 PyTorch 的开源 Python 工具包，用于说话人分离和说话人嵌入。&lt;/p>
&lt;h3 id="nvidia-nemo">Nvidia NeMo&lt;/h3>
&lt;p>Nvidia NeMo 采用了不同的方法，使用多尺度分割和 Neural Diarizer（MSDD 模型）来处理说话人重叠语音。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-speaker-diarization/sd-nemo-pipeline.png"
 alt="Nvidia NeMo 说话人分离流程"
 loading="lazy"
 decoding="async" width="1666" height="484">
&lt;/p>
&lt;h3 id="多尺度分割">多尺度分割&lt;/h3>
&lt;p>NeMo 解决了说话人识别质量与时间粒度之间的权衡问题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>较长片段&lt;/strong> → 说话人表征质量更高，但时间分辨率较低&lt;/li>
&lt;li>&lt;strong>较短片段&lt;/strong> → 说话人表征质量较低，但时间分辨率较高&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-speaker-diarization/sd-multiscale.png"
 alt="多尺度分割"
 loading="lazy"
 decoding="async" width="1828" height="500">
&lt;/p></description></item><item><title>基于自注意力模型的音节级发音重音检测</title><link>https://voiceping.net/zh/blog/research-pronunciation-stress/</link><pubDate>Wed, 15 Nov 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-pronunciation-stress/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>注：&lt;/strong> 已在 arXiv 发表：&lt;a href="https://arxiv.org/abs/2311.00301">arXiv:2311.00301&lt;/a>
&lt;/p>&lt;/blockquote>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>有效口语交流的前提之一是单词发音清晰，这对非母语者尤为重要。单词重音是清晰准确英语的关键，音节重音的错误放置可能导致误解。因此，了解重音级别对英语使用者和学习者至关重要。&lt;/p>
&lt;p>本文提出了一种&lt;strong>自注意力模型&lt;/strong>，用于识别英语口语中每个音节的重音级别。&lt;/p>
&lt;p>&lt;strong>主要成果：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>最简单的模型在一个数据集上达到 &lt;strong>88% 以上的准确率&lt;/strong>&lt;/li>
&lt;li>在另一个数据集上达到 &lt;strong>93% 以上的准确率&lt;/strong>&lt;/li>
&lt;li>更高级的模型实现了更高的准确率&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>有效的口语交流需要清晰的发音，对于英语非母语者来说更是如此。单词重音的位置对于语言的可理解性至关重要——音节重音放错位置可能导致误解或沟通障碍。&lt;/p>
&lt;p>本研究致力于解决音节级别重音的自动检测问题，在以下领域具有应用前景：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>在线会议&lt;/strong> — 实时发音反馈&lt;/li>
&lt;li>&lt;strong>英语学习&lt;/strong> — 帮助学习者改善重音模式&lt;/li>
&lt;li>&lt;strong>语音分析&lt;/strong> — 英语口语的自动评估&lt;/li>
&lt;/ul>
&lt;h2 id="2-方法">2. 方法&lt;/h2>
&lt;h3 id="特征分析">特征分析&lt;/h3>
&lt;p>模型分析了多种韵律特征和类别特征：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>特征类型&lt;/th>
 &lt;th>说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>音高水平&lt;/strong>&lt;/td>
 &lt;td>音节的基频&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>强度&lt;/strong>&lt;/td>
 &lt;td>音节的响度/振幅&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>时长&lt;/strong>&lt;/td>
 &lt;td>音节的时间长度&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>音节类型&lt;/strong>&lt;/td>
 &lt;td>音节结构的分类&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>音核特征&lt;/strong>&lt;/td>
 &lt;td>各音节中元音（音核）的属性&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="自注意力架构">自注意力架构&lt;/h3>
&lt;p>自注意力机制使模型能够：&lt;/p>
&lt;ol>
&lt;li>考虑单词内音节之间的关系&lt;/li>
&lt;li>对不同韵律特征的重要性进行加权&lt;/li>
&lt;li>捕捉重音分配中的上下文模式&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>输入：每个音节的韵律特征
 ↓
自注意力层
 ↓
输出：每个音节的重音级别预测
&lt;/code>&lt;/pre>&lt;h2 id="3-结果">3. 结果&lt;/h2>
&lt;h3 id="性能概要">性能概要&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>模型版本&lt;/th>
 &lt;th>数据集 1&lt;/th>
 &lt;th>数据集 2&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>最简单模型&lt;/td>
 &lt;td>88% 以上&lt;/td>
 &lt;td>93% 以上&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>高级模型&lt;/td>
 &lt;td>更高&lt;/td>
 &lt;td>更高&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>要点：&lt;/strong> 实验证明自注意力架构在重音检测方面效果显著，能够捕捉决定重音模式的音节间上下文关系。&lt;/p></description></item><item><title>提升机器翻译中的 In-Context Learning 性能</title><link>https://voiceping.net/zh/blog/research-icl-translation/</link><pubDate>Sun, 15 Oct 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-icl-translation/</guid><description>&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>大语言模型（LLM）通过以输入-标签对作为条件，在下游任务中展现出了出色的能力。这种推理方式被称为 &lt;strong>In-Context Learning&lt;/strong>（Brown et al. 2020）。GPT-4 无需微调，仅通过提供特定任务示例即可提升翻译能力。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-icl-translation/figure1.png"
 alt="图 1：使用 Few-shot 示例进行中英 In-Context Learning 翻译"
 loading="lazy"
 decoding="async" width="1366" height="648">
&lt;/p>
&lt;p>In-Context Learning 的有效性源于隐式贝叶斯推断（Xie et al. 2022）。随机选择示例无法有效帮助 GPT-4 理解提示的概念。本研究的主要目标是基于用户输入，策略性地选择合适的示例。&lt;/p>
&lt;h2 id="2-方法">2. 方法&lt;/h2>
&lt;p>本方法假设可以访问包含翻译对的数据集 Ds。文本检索器（Gao 2023）从中定位并选取与用户提示语义最相似的前 K 个句子。&lt;/p>
&lt;p>检索器由两个组件构成：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>TF-IDF 矩阵&lt;/strong> — 衡量词频和逆文档频率&lt;/li>
&lt;li>&lt;strong>余弦相似度&lt;/strong> — 计算 TF-IDF 向量之间的相似度&lt;/li>
&lt;/ol>
&lt;h3 id="tf-idf-分数">TF-IDF 分数&lt;/h3>
&lt;p>TF-IDF 分数衡量词语在文档中的重要程度：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TF（词频）&lt;/strong>：词语在文档中出现的频率&lt;/li>
&lt;li>&lt;strong>IDF（逆文档频率）&lt;/strong>：词语在整个语料库中的重要性&lt;/li>
&lt;/ul>
&lt;h3 id="余弦相似度">余弦相似度&lt;/h3>
&lt;p>余弦相似度通过考量两个向量表示之间的夹角来评估相似性。分数越高，表示用户提示与数据集文档之间的相似度越大。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-icl-translation/figure2.png"
 alt="图 2：利用 TF-IDF 矩阵和余弦相似度从数据集中选取前 K 个示例"
 loading="lazy"
 decoding="async" width="1370" height="666">
&lt;/p>
&lt;h2 id="3-实验设置">3. 实验设置&lt;/h2>
&lt;h3 id="31-实验流程">3.1 实验流程&lt;/h3>
&lt;p>实验涵盖三种场景：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>无 ICL&lt;/strong>：不使用 In-Context Learning 示例的 GPT-4 翻译&lt;/li>
&lt;li>&lt;strong>随机 ICL&lt;/strong>：随机选择翻译示例&lt;/li>
&lt;li>&lt;strong>本文方法&lt;/strong>：TF-IDF 检索器根据相似度分数选取前 4 个示例&lt;/li>
&lt;/ol>
&lt;h3 id="评估指标">评估指标&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>BLEU 分数&lt;/strong>：将翻译片段与参考译文进行对比（Papineni et al. 2002）&lt;/li>
&lt;li>&lt;strong>COMET 分数&lt;/strong>：与人工判断达到最先进相关性的多语言机器翻译评估神经框架（Rei et al. 2020）&lt;/li>
&lt;/ul>
&lt;h3 id="32-数据集">3.2 数据集&lt;/h3>
&lt;p>选择 &lt;strong>OPUS-100&lt;/strong>（Zhang et al. 2020）的原因：&lt;/p></description></item><item><title>机器翻译精度评估与改进方法</title><link>https://voiceping.net/zh/blog/research-mt-evaluation/</link><pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-mt-evaluation/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>我们致力于解决机器翻译质量的准确评估问题，同时努力将翻译精度提升至人工翻译水平。本研究采用5个不同的基准翻译模型，通过3种评估指标对其性能进行衡量，并结合先前研究的成果不断优化模型精度。&lt;/p>
&lt;h2 id="目录">目录&lt;/h2>
&lt;ol>
&lt;li>引言&lt;/li>
&lt;li>数据集&lt;/li>
&lt;li>机器翻译精度评估方法
&lt;ul>
&lt;li>3.1. BLEU 分数&lt;/li>
&lt;li>3.2. BLEURT 分数&lt;/li>
&lt;li>3.3. COMET 分数&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>五个基准机器翻译模型及其精度
&lt;ul>
&lt;li>4.1. Azure 基线模型&lt;/li>
&lt;li>4.2. Azure 自定义模型&lt;/li>
&lt;li>4.3. DeepL 模型&lt;/li>
&lt;li>4.4. Google 翻译&lt;/li>
&lt;li>4.5. GPT-4 模型&lt;/li>
&lt;li>4.6. 对比与结论&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>提升机器翻译精度
&lt;ul>
&lt;li>5.1. GPT-4 的上下文学习&lt;/li>
&lt;li>5.2. 混合模型&lt;/li>
&lt;li>5.3. GPT-4 作为数据清洗工具&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>结论&lt;/li>
&lt;li>参考文献&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="1-引言">1. 引言&lt;/h2>
&lt;p>随着 AI 技术的进步，特别是 OpenAI 推出 ChatGPT 之后，人们对 AI 行业的信任度不断提升。作为自然语言处理领域的核心技术，机器翻译正变得愈发重要。&lt;/p>
&lt;p>本文重点评估了5个基础翻译模型的性能，采用多种评估指标进行对比，同时深入探讨了尽可能提升模型精度的方法。&lt;/p>
&lt;h2 id="2-数据集">2. 数据集&lt;/h2>
&lt;p>本研究使用 Hugging Face 上的 &lt;strong>Opus100（ZH-EN）数据集&lt;/strong>。该数据集包含100万条跨领域的中英翻译实例，是训练翻译模型的理想选择。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-mt-evaluation/opus100-dataset.png"
 alt="Opus100 数据集"
 loading="lazy"
 decoding="async" width="1600" height="198">
&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>注意：&lt;/strong> 必须指出，数据集中存在翻译错误。虽然这些错误看似会降低训练精度，但同时也有助于防止过拟合问题。&lt;/p>&lt;/blockquote>
&lt;p>此外，在将数据集整合到 Azure AI 平台之前，需要进行预处理以去除每个句子中的异常符号。&lt;/p></description></item><item><title>日语与越南语 ASR 模型微调</title><link>https://voiceping.net/zh/blog/research-asr-finetuning/</link><pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-asr-finetuning/</guid><description>&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>在通信技术快速发展的背景下，以 OpenAI Whisper 模型为代表的最新突破显著提升了多语言语音转文字的准确性和可及性。然而，在识别精度方面仍有提升空间。本研究专注于越南语和日语的自动语音识别（ASR）模型性能优化。&lt;/p>
&lt;p>我们采用标准指标进行评估：越南语使用词错误率（WER），日语使用字符错误率（CER）。&lt;/p>
&lt;p>&lt;strong>核心结果：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>越南语（FOSD + Common Voice + Google Fleurs + Vivos）：&lt;strong>WER 9.46%&lt;/strong>&lt;/li>
&lt;li>日语（ReazonSpeech + Common Voice + Google Fleurs）：&lt;strong>CER 8.15%&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="目录">目录&lt;/h2>
&lt;ol>
&lt;li>背景介绍&lt;/li>
&lt;li>环境搭建&lt;/li>
&lt;li>数据集加载&lt;/li>
&lt;li>数据预处理&lt;/li>
&lt;li>训练&lt;/li>
&lt;li>参数高效微调&lt;/li>
&lt;li>结果&lt;/li>
&lt;li>评估&lt;/li>
&lt;li>Azure Speech Studio&lt;/li>
&lt;li>总结&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="1-背景介绍">1. 背景介绍&lt;/h2>
&lt;p>在当今社会，通信与技术已不可或缺，但在可及性、包容性和高效知识传播方面仍面临诸多挑战。自动语音识别（ASR）技术的进步正在简化人机交互，尤其体现在在线会议场景中。&lt;/p>
&lt;p>ASR 是将语音信号转换为对应文本的过程。近年来，随着大规模语音数据集及其转录文本的可用性提高，各大企业纷纷关注这一领域。&lt;/p>
&lt;p>&lt;img
 src="https://voiceping.net/en/blog/research-asr-finetuning/whisper-architecture.jpeg"
 alt="OpenAI Whisper 架构"
 loading="lazy"
 decoding="async" width="1380" height="548">
&lt;/p>
&lt;p>OpenAI Whisper 是一个基于 Transformer 的编码器-解码器模型，采用 sequence-to-sequence 架构设计。它以音频频谱图特征作为输入，将其转换为文本 token 序列。具体过程如下：&lt;/p>
&lt;ol>
&lt;li>特征提取器将原始音频转换为 log-Mel 频谱图&lt;/li>
&lt;li>Transformer 编码器生成编码器隐藏状态序列&lt;/li>
&lt;li>解码器通过 cross-attention 机制预测文本 token&lt;/li>
&lt;/ol>
&lt;h2 id="2-环境搭建">2. 环境搭建&lt;/h2>
&lt;p>Whisper 微调有两种方式：使用 Google Colab，或在本地 PC 上运行代码。&lt;/p></description></item><item><title>自动语音识别大语言模型的训练、评估与部署</title><link>https://voiceping.net/zh/blog/research-asr-llm-training/</link><pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-asr-llm-training/</guid><description>&lt;p>&lt;strong>作者&lt;/strong>：Linchuan Du
&lt;strong>单位&lt;/strong>：The University of British Columbia 数学系
&lt;strong>日期&lt;/strong>：2023年8月&lt;/p>
&lt;h2 id="摘要">摘要&lt;/h2>
&lt;p>自动语音识别（ASR），也称为语音转文字（STT），利用深度学习技术将含有语音的音频转录为文字。大语言模型（LLM）模拟人脑处理词语和短语的方式，具备理解和生成文本数据的能力。LLM 通常包含数百万个权重，并使用各类数据集进行预训练。ASR LLM 通过特征提取和分词（tokenization）将音频输入转换为所需的输入格式。&lt;/p>
&lt;p>为了定制具有理想性能的 ASR LLM，我们首先在 Google Colaboratory 上测试了 OpenAI 开发的 Whisper 微调流程。随后将较大模型部署到配备 GPU 的 Windows 环境中，以加速训练并缓解 Colab 和 macOS 上的 GPU 限制问题。我们基于音频质量和转录准确性等信息对音频数据的可靠性进行了评估，并通过数据预处理和超参数调优技术改进和优化了模型。当常规微调无法解决 GPU 内存问题时，采用了基于 LoRA 的参数高效微调（PEFT），冻结大部分参数以节省内存，同时尽量减少性能损失。&lt;/p>
&lt;p>我们还探索了利用 Neural Speaker Diarization 为 Whisper 添加多说话人支持的可能性。通过 Pipeline 和 WhisperX 实现了与 Pyannote 的集成。WhisperX 提供了词级时间戳和语音活动检测（VAD）等额外功能。&lt;/p>
&lt;p>除 Whisper 外，我们还安装并比较了具有 ASR 功能的其他模型，包括 Meta AI 的 MMS、PaddleSpeech、SpeechBrain 和 ESPNet。使用中文数据集进行了 CER 指标的比较评估。此外，还引入了 Azure AI 的 Custom Speech 进行实时 STT 性能对比（主要针对普通话）。&lt;/p></description></item><item><title>通过 Voice Activity Detection 降低语音识别使用量和成本</title><link>https://voiceping.net/zh/blog/research-voice-activity-detection-cost-reduction/</link><pubDate>Fri, 10 Feb 2023 00:00:00 +0000</pubDate><guid>https://voiceping.net/zh/blog/research-voice-activity-detection-cost-reduction/</guid><description>&lt;p>&lt;img
 src="https://voiceping.net/images/blog/ja/Reducing-Speech-to-Text-usage-and-costs-using-Voice-Activity-Detection-1-1024x509-1.jpeg"
 alt="Image"
 loading="lazy"
 decoding="async" width="1024" height="509">
&lt;/p>
&lt;p>本文详细介绍了 VoicePing 中 Speech to Text 的实现细节，以及开发团队如何最大限度地提高云服务的使用效率。&lt;/p>
&lt;p>VoicePing 功能丰富，是远程团队的理想解决方案！我们目前提供为期一年的免费高级订阅，前往 &lt;a href="https://voiceping.net/">https://voiceping.net/&lt;/a>
 即可开始使用！&lt;/p>
&lt;h4 id="摘要">摘要&lt;/h4>
&lt;p>从零开始实现 Speech-to-Text 并获得良好的识别精度非常困难。因此，许多企业和开发者选择使用已有的 SaaS 方案，这些方案具有出色的识别效果，并支持多种语言。&lt;/p>
&lt;p>根据使用量的不同，这可以是一个低成本的解决方案，因为收费方式是&amp;quot;按量付费&amp;quot;。但这也意味着使用量过多时成本会很高。最终取决于使用方式和使用量。&lt;/p>
&lt;p>在这篇文章中，我们将介绍 VoicePing 用来降低会议中用户音频 STT 处理高成本的策略。这一策略之所以可行，是因为在会议中大多数用户只是在听，会议大部分时间并不发言。该策略基于使用 Voice Activity Detection（VAD）库来避免将无声音频流传输到 STT 服务。&lt;/p>
&lt;p>我们还将展示在实现这一策略过程中遇到的所有问题及其解决方法。&lt;/p>
&lt;h4 id="引言">引言&lt;/h4>
&lt;p>Speech-to-Text（STT），也称为自动语音识别（ASR），是一项有着广泛应用场景的功能。例如 YouTube 上的自动字幕生成、Siri、Alexa 和 Cortana 等个人虚拟助手，以及许多其他类型的语音应用。&lt;/p>
&lt;p>在 VoicePing 中，我们用它来在会议中展示实时转写，使得在转写基础上显示实时翻译成为可能。还可以设置自动将这些转写同步到 Slack 工作区的公共或私有频道，安全保存公司所有工作相关讨论的通信记录。&lt;/p>
&lt;p>同步到 Slack 的转写可以利用 Slack 提供的各种功能，例如将会议中分配给你的任务相关消息加书签，将特定讨论事项固定在频道中确保团队不会忘记，或者在会议提前结束、时间不够的情况下在 Slack 线程中继续讨论。&lt;/p>
&lt;h4 id="实现">实现&lt;/h4>
&lt;p>实现一个能够将音频转换为文本的 AI 系统并不容易，需要大量带有转写文本的音频文件来训练和验证 AI 模型，支持的语言越多，工作量就越大。&lt;/p>
&lt;p>幸运的是，现有许多可用的服务，而且这些服务的质量每天都在提高，在某些情况下其准确度可以与专业的人工转写人员相媲美。但根据应用的用户数量和收入情况，这些费用可能过高且不可持续。我可以建议两种解决成本问题的方案：&lt;/p>
&lt;p>第一种方案是最便宜的选择，使用免费服务。大多数服务都有免费层级，对并发使用量和使用时长有限制。如果免费层级不够用，我不知道有任何不收费的 SaaS 方案，但有一个实验性的 Web Speech API。一些浏览器已经实现了它，如 Google Chrome 和 Microsoft Edge。&lt;/p>
&lt;p>这些都很好，但仍有局限性。作为实验性 API，并非所有浏览器都支持，要求用户使用其他浏览器可能会影响应用声誉。另一个限制是 API 本身，目前无法选择使用哪个输入设备，调用 .start() 后总是从默认输入设备开始录音。&lt;/p></description></item></channel></rss>