PyTorch 性能剖析(第 2 部分):从 nn.Linear 到融合 MLP

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/torch-mlp-fusion.md">在 GitHub 上更新</a></div> <p></p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/thumbnail.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/oA2BCRgyXSBc9O4Vi2liUonuJwEYVSh2rgYMIy6r5lY/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL3RodW1ibmFpbC5wbmc" alt="博客文章缩略图" referrerpolicy="no-referrer"></a><p></p> <p>在 <a href="https://huggingface.co/blog/torch-profiler">「PyTorch 性能剖析 (profiling)」系列的第一部分</a> 中,我们用 <code>torch.add(torch.matmul(x, w), b)</code> 学习了如何阅读 PyTorch 性能剖析器轨迹。沿途还讨论了几个相关主题:CPU 调度链、启动开销、开销受限与计算受限两种状态的区别,以及 <code>torch.compile</code> 的一些内部机制。</p> <p>到了第二篇(也就是本文),我们再向上迈一步。我们会把手写的矩阵乘加组合替换为 <code>nn.Linear</code>(设置 <code>bias=True</code>)。这是每个深度学习模型都会用到的基础构件。随后,我们会把三个 <code>nn.Linear</code>(本例中的具体设置)堆叠起来,并在中间加入激活函数,构成一个多层感知器(MLP)模块。</p> <blockquote class="note"> <p>本文脚本在这里:<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/02_linear.py"><code>02_linear.py</code></a>、<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/03_simple_mlp.py"><code>03_simple_mlp.py</code></a> 和 <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/03_kernels_mlp.py"><code>03_kernels_mlp.py</code></a>。和上一篇一样,建议在单独的标签页打开脚本,边读文章边对照代码。本文使用 <code>NVIDIA A100-SXM4-80GB</code> GPU 运行脚本。在 Hugging Face 基础设施上启动 GPU 并通过 <a href="https://huggingface.co/docs/hub/spaces-dev-mode">Spaces Dev Mode</a> 运行这些脚本很方便。你也可以用 <a href="https://huggingface.co/docs/huggingface_hub/en/guides/jobs">Hugging Face Jobs pipeline</a> 执行脚本。</p> </blockquote> <p>开始之前,先快速回顾两个后文会反复用到的概念:</p> <ol> <li>GPU <strong>内核(kernel)</strong> 是在 GPU 的大量线程上并行运行的程序。</li> <li>CPU 负责<strong>调度并启动</strong>这些内核。在 PyTorch 性能轨迹中看到的大部分开销,都是这类调度工作。</li> </ol> <h2 class="relative group flex items-baseline"> <a id="从-matmul-add-到-linear" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E4%BB%8E-matmul-add-%E5%88%B0-linear" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 从 matmul-add 到 Linear </span> </h2> <p><code>nn.Linear</code> 是对我们在 <a href="https://huggingface.co/blog/torch-profiler">第 1 部分</a> 中已经剖析过的同一组矩阵乘法与加法的模块封装。唯一的区别是,它把权重和偏置作为参数持有,并暴露出 PyTorch 用户熟悉的 <code>forward</code> 方法。</p> <pre><code class="language-py"><span class="hljs-comment"># bias=True would truly emulate the multiplication and addition</span> <span class="hljs-comment"># operations we have seen in part 1 of the series</span> linear_layer = nn.Linear(in_dim, out_dim, bias=<span class="hljs-literal">True</span>) y = linear_layer(x) </code></pre> <p>当前操作可以写成:</p> <pre><code>y = x @ w.T + b </code></pre> <p>其中 <code>x</code> 是输入,<code>w</code> 是权重,<code>b</code> 是偏置。运行 <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/02_linear.py"><code>02_linear.py</code></a>,看看性能剖析结果。</p> <pre><code class="language-bash">uv run 02_linear.py --batch 1024 --in_dim 32 --out_dim 64 uvx trace-util traces -b traces </code></pre> <blockquote class="tip"> <p><a href="https://x.com/ariG23498/status/2054811716727517374" rel="nofollow"><code>trace-util</code></a> 是一个工具,可以把轨迹同步到 <a href="https://huggingface.co/storage">Hugging Face bucket</a>,并在终端中给出 <a href="https://perfetto.dev/" rel="nofollow">Perfetto URL</a>。</p> </blockquote> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/linear-profile-trace.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/9v-wc9OB2Cf05doY8N2TKDCPqSBQky4yEQIOOCHu7c4/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2xpbmVhci1wcm9maWxlLXRyYWNlLnBuZw" alt="一次 `nn.Linear` 前向传播的 PyTorch 性能轨迹:CPU 时间线上有三个较短的 Profile Step 和 `linear_fwd` 标注,GPU 时间线上有一个很小的内核,末尾还有一条较长的 `cudaDeviceSynchronize`" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 1:<code>nn.Linear</code> 的性能轨迹</td> </tr> </tbody> </table> </div> <p>图 1 展示了一次线性层 <code>forward</code> 调用的性能轨迹。我们用和前文轨迹类似的 <code>schedule</code> 设置来追踪线性层的 <code>forward</code> 调用,其中 <code>wait=1</code>、<code>warmup=1</code>、<code>active=3</code>。这就是为什么 CPU 和 GPU 时间线中会看到三个 Profile Step。</p> <h3 class="relative group flex items-baseline"> <a id="转置在做什么?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E8%BD%AC%E7%BD%AE%E5%9C%A8%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 转置在做什么? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/transpose-cpu-dispatch.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/gTcTQBdMSkeAT3VPD5OnulgM_ttwzYAViy3el4iz4AA/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL3RyYW5zcG9zZS1jcHUtZGlzcGF0Y2gucG5n" alt="放大后的 CPU 调度链,显示 aten::linear 内部的 aten::t 转置算子嵌套在 aten::addmm 之前,GPU 时间线上没有对应活动" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 2:转置对应的 CPU 行</td> </tr> </tbody> </table> </div> <p>如果像图 2 那样放大性能轨迹,会发现 <code>aten::addmm</code>(乘法与加法)之前有一个 <code>aten::t</code>(转置)算子。由此可以看出,<code>nn.Linear</code> 会先转置权重参数,再与输入相乘。这就是轨迹里出现 <code>aten::t</code> 的原因。</p> <p>需要注意的是,<code>aten::t</code> 并不会真正复制或重新组织数据:它只是在 CPU 上重写张量元数据(形状和步长),用来表示转置后的矩阵。它不会在 GPU 上启动内核。可以通过两种方式验证这一点:查看轨迹中的 GPU 时间线,或查看性能剖析表里 <code>aten::t</code> 这一行及其 CUDA 耗时。</p> <h3 class="relative group flex items-baseline"> <a id="为什么没有单独的-mul-和-add-内核?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E6%9C%89%E5%8D%95%E7%8B%AC%E7%9A%84-mul-%E5%92%8C-add-%E5%86%85%E6%A0%B8%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么没有单独的 <code>mul</code> 和 <code>add</code> 内核? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/no-aten-add.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/igh0GVARwuNSo-RWjRxeuphE0aM2yaj7vEE1PuWBSGY/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL25vLWF0ZW4tYWRkLnBuZw" alt="线性层性能轨迹中高亮了调度链,显示 aten::linear、aten::t 和 aten::addmm,但没有单独的 aten::add 算子" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 3:线性层的性能轨迹中没有 <code>aten::add</code></td> </tr> </tbody> </table> </div> <p>如图 3 所示,线性层的调度链中没有 <code>aten::add</code>(偏置加法)。原因是偏置加法已经被 <em>折叠</em> 到矩阵乘法内核里,这种做法称为 <strong>epilogue(收尾阶段)</strong>。</p> <p><strong>Epilogue</strong> 是 GEMM(GEneral Matrix Multiply,通用矩阵乘)内核在把结果写回 HBM(High Bandwidth Memory,高带宽内存,也就是 GPU 主内存)之前,于最后阶段执行的一小段计算。添加偏置、应用激活函数、乘以常数缩放,都是典型的 epilogue。Epilogue 的意义在于避免第二次从 HBM 读取或写入数据,因为内存流量会显著增加操作成本。</p> <p><code>nn.Linear</code> 会调用 <code>torch.nn.functional.linear</code>,后者再调用 <code>aten::linear</code>。<code>aten::linear</code> 查看输入,发现传入了偏置,于是调度 <code>aten::addmm(bias, x, weight)</code>,而不是把 matmul 和 add 分开执行。<code>addmm</code> 计算的是:</p> <pre><code>out = x @ weight.T + bias </code></pre> <p>在 GPU 上运行的 cuBLAS GEMM 内核内置了偏置相加变体,<code>aten::addmm</code> 选择的正是这个内核。加法不会以单独内核的形式出现,因为它是 <strong>matmul 内核写回阶段的一部分</strong>,这正是 epilogue 的含义。</p> <p>这里可以注意一个细节。<a href="https://huggingface.co/blog/torch-profiler#did-we-fuse-the-matmul-and-add-kernels-into-one">第 1 部分 <code>--compile</code> 小节</a> 中出现的那个内核(<code>addmm</code>),正是 eager 模式下 <code>nn.Linear</code> 已经在用的内核。这里已经没有什么可供 <code>torch.compile</code> 继续融合了。下一步我们会验证这一点。</p> <h3 class="relative group flex items-baseline"> <a id="--compile-能帮助单个-linear-吗?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#--compile-%E8%83%BD%E5%B8%AE%E5%8A%A9%E5%8D%95%E4%B8%AA-linear-%E5%90%97%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> --compile 能帮助单个 Linear 吗? </span> </h3> <p>我们先编译 <code>forward</code> 调用,再查看性能轨迹。(性能轨迹会在<a href="https://huggingface.co/blog/zh/torch-mlp-fusion#where-did-the-transpose-go-kernel-layouts-and-pre-ops" rel="nofollow">下一节</a>中可视化。)</p> <pre><code class="language-bash">uv run 02_linear.py --batch 1024 --in_dim 32 --out_dim 64 --compile uvx trace-util traces -b traces </code></pre> <p>如果对比单个 <code>nn.Linear</code> 的 <code>forward</code> 在 eager 与 compile 模式下的轨迹,会发现:</p> <ul> <li>GPU 上是同一个 cuBLAS GEMM 内核。</li> <li>CPU 上是同一个 <code>aten::addmm</code> 算子。</li> <li>CPU 时间线上多了几行 compile 独有的事件。</li> </ul> <p>这一点值得记住。常见反应是,只要模型变慢就想上 <code>torch.compile</code>。但对于单个带偏置的 GEMM,compile 几乎没有发挥空间。这不是 bug,而是因为 compile 至少需要不止一个操作,才可能做出融合。接下来我们通过 <a href="https://huggingface.co/blog/zh/torch-mlp-fusion#stacking-two-linears-the-mlp" rel="nofollow">MLP</a> 来证明这一点。</p> <p><a id="where-did-the-transpose-go-kernel-layouts-and-pre-ops" rel="nofollow"></a></p> <h3 class="relative group flex items-baseline"> <a id="转置去哪了?内核布局与前置操作" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E8%BD%AC%E7%BD%AE%E5%8E%BB%E5%93%AA%E4%BA%86%EF%BC%9F%E5%86%85%E6%A0%B8%E5%B8%83%E5%B1%80%E4%B8%8E%E5%89%8D%E7%BD%AE%E6%93%8D%E4%BD%9C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 转置去哪了?内核布局与前置操作 </span> </h3> <p>仔细阅读两份轨迹(eager 与 compile)的读者会注意到,eager 模式下的 CPU 调度链比编译后的调度链更长。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/eager.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/WID4ByWhK-j5mX2lQD-Jwf4UUejVM5mEGf8qyivDa1E/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2VhZ2VyLnBuZw" alt="Eager 模式下的 CPU 调度链,其中 aten::linear 下面的 aten::t 转置和 aten::addmm 分别被框出" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 4:Eager 调度链中,<code>aten::linear</code> 依次经过 <code>aten::t</code>(转置)和 <code>aten::addmm</code></td> </tr> </tbody> </table> </div> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/compile.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/rvScQs5TEybhtI7YpOoOoPIAjw3zKajlWUeZZCvX6wU/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2NvbXBpbGUucG5n" alt="编译后的 CPU 调度链,显示一个 Torch-Compiled Region 和一次 aten::addmm 调用,没有转置算子" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 5:编译后的调度链直接调用 <code>aten::addmm</code>,没有转置</td> </tr> </tbody> </table> </div> <p>Eager 模式下,<code>aten::linear</code> 内部的 CPU 调度链是 <code>aten::t</code> 后接 <code>aten::addmm</code>(图 4)。要理解 <code>aten::t</code> 究竟做了什么,需要先绕到 <em>stride(步长)</em> 和 <em>view(视图)</em> 上。</p> <p>张量在内存中以一段连续平坦的数字序列来存储自身数据。<code>shape</code> 和 <code>stride</code> 是覆盖在这段数据上的元数据,用来告诉 PyTorch 如何遍历它:步长 <code>(s0, s1)</code> 表示「移动到下一行需要跨过 <code>s0</code> 个元素,移动到下一列需要跨过 <code>s1</code> 个元素」。只改元数据,就能得到同一份原始数据的不同 <em>view</em>,无需复制:</p> <pre><code class="language-py"><span class="hljs-meta">&gt;&gt;&gt; </span>M = torch.tensor([[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>], <span class="hljs-meta">... </span> [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>], <span class="hljs-meta">... </span> [<span class="hljs-number">4</span>, <span class="hljs-number">5</span>]]) <span class="hljs-meta">&gt;&gt;&gt; </span>M.shape, M.stride() (torch.Size([<span class="hljs-number">3</span>, <span class="hljs-number">2</span>]), (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>)) <span class="hljs-comment"># two steps per row, one step per column</span> <span class="hljs-meta">&gt;&gt;&gt; </span>T = M.t() <span class="hljs-comment"># transpose</span> <span class="hljs-meta">&gt;&gt;&gt; </span>T.shape, T.stride() (torch.Size([<span class="hljs-number">2</span>, <span class="hljs-number">3</span>]), (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)) <span class="hljs-comment"># shape and stride swapped, data untouched</span> <span class="hljs-meta">&gt;&gt;&gt; </span>T tensor([[<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>]]) <span class="hljs-meta">&gt;&gt;&gt; </span>T.flatten() <span class="hljs-comment"># forced to materialize, so the data is reordered</span> tensor([<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>]) </code></pre> <p><code>M.t()</code> 没有移动任何一个数字。它返回了一个新视图,交换了步长,因此现在按行读取时,会以转置后的顺序遍历原始缓冲区 <code>0, 1, 2, 3, 4, 5</code>。底层数据完全相同,只有元数据不同。</p> <p>这正是线性层内部 <code>aten::t</code> 的行为:它不会分配新张量,也不会复制任何数据,只是生成一个重写了步长的权重 <em>view</em>。</p> <p>从图 5 可以看出,compile 并没有移除某个 GPU 内核;它移除的是调度这个视图带来的 <em>CPU 开销</em>。Inductor 在编译时追踪了整个视图链,一次性算出最终步长,并发出一个直接的 <code>aten::addmm</code> 调用,把这些步长硬编码进去。几微秒的 CPU 工作消失了,而 GPU 执行的是完全相同的数学计算。</p> <p>也正如预期,如果输入数据不满足编译器预先计算好的步长约束,就会抛出错误。</p> <p>如果查看两份轨迹的 GPU 时间线,会看到每次 forward 都恰好只有一个内核,而且两次都是 <em>同一个</em> 内核:</p> <pre><code>cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_32x32_32x1_tn_align8 </code></pre> <p>既然没有运行转置内核,那么是谁让 GEMM 按转置后的顺序读取权重矩阵的?答案就在内核名中。看看后缀:</p> <pre><code>cutlass_80_wmma_tensorop_bf16_s161616gemm_bf16_32x32_32x1_tn_align8 ^^ </code></pre> <p>这个 <code>tn</code> 就是布局描述符。cuBLAS 和 CUTLASS 会针对不同输入布局组合预编译 <em>不同的内核二进制</em>。</p> <p><code>n</code>(non-transposed,未转置)和 <code>t</code>(transposed,转置)描述了内核在内层循环中如何遍历输入。调度器的工作是查看输入步长,判断哪种后缀组合匹配,并选择对应的预编译内核。</p> <blockquote class="tip"> <p>性能轨迹里的内核名是内核身份信息的一种摘要。如果两次运行显示同一个内核名,GPU 做的就是同一类工作。如果名称不同(例如 <code>_tn_</code> 与 <code>_nn_</code>、<code>bf16</code> 与 <code>fp16</code>,或 <code>s16816gemm</code> 与 <code>s161616gemm</code>),GPU 做的工作就不同,说明调度器走了另一条分支。学会阅读内核名,是对比性能轨迹时最有用的习惯之一。</p> </blockquote> <p><a id="stacking-two-linears-the-mlp" rel="nofollow"></a></p> <h2 class="relative group flex items-baseline"> <a id="堆叠三个-linear:mlp" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E5%A0%86%E5%8F%A0%E4%B8%89%E4%B8%AA-linear%EF%BC%9Amlp" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 堆叠三个 Linear:MLP </span> </h2> <p>本节会剖析一个多层感知机(MLP)。为了让例子更有意思,我们会剖析一个使用 GeGLU 激活变体的前馈网络(它在实践中相当常用)。这也是我们向深度学习研究史上最伟大的结尾句之一致敬的方式(图 6)。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/geglu-paper.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/R2Nkp_m8Y3VDW-KvzLfF4HaU5Bav6vONu1j5yT6TGoY/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2dlZ2x1LXBhcGVyLnBuZw" alt="GLU Variants Improve Transformer 论文的结论部分,其中高亮了结尾句:将这些架构的成功归功于神圣仁慈" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 6:<a href="https://arxiv.org/abs/2002.05202" rel="nofollow">GLU Variants Improve Transformer</a> 论文的结论部分。</td> </tr> </tbody> </table> </div> <pre><code class="language-py"><span class="hljs-keyword">class</span> <span class="hljs-title class_">SimpleGeGLUMLP</span>(nn.Module): <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, dim, hidden</span>): <span class="hljs-built_in">super</span>().__init__() self.gate_proj = nn.Linear(dim, hidden, bias=<span class="hljs-literal">False</span>) self.up_proj = nn.Linear(dim, hidden, bias=<span class="hljs-literal">False</span>) self.down_proj = nn.Linear(hidden, dim, bias=<span class="hljs-literal">False</span>) <span class="hljs-keyword">def</span> <span class="hljs-title function_">forward</span>(<span class="hljs-params">self, x</span>): g = self.gate_proj(x) u = self.up_proj(x) h = F.gelu(g, approximate=<span class="hljs-string">"tanh"</span>) m = h * u y = self.down_proj(m) <span class="hljs-keyword">return</span> y </code></pre> <p>完整脚本在这里:<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/03_simple_mlp.py"><code>03_simple_mlp.py</code></a>。执行方式如下:</p> <pre><code class="language-bash">uv run 03_simple_mlp.py --batch 64 --<span class="hljs-built_in">seq</span> 128 --dim 768 --hidden 3072 uvx trace-util traces -b traces </code></pre> <p>打开轨迹之前,先一起想想预期会看到什么。<code>forward</code> 函数做了不少计算,但大部分内容已经很熟悉。</p> <p>我们应该会看到三次 <code>aten::linear</code> 调度,对应三个 <code>nn.Linear</code> 层。还应该看到两次逐元素内核启动:一次用于 GeLU,一次用于乘法。查看轨迹之前先形成预期,是性能剖析过程中最有用的习惯:读轨迹是为了 <em>验证或推翻</em> 猜测,而不是从零开始形成猜测。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/simple-mlp-eager.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/6vPVFOhbV-B8zpCtvcVaZsYWqVwO0Xhq24NTNVwjILM/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL3NpbXBsZS1tbHAtZWFnZXIucG5n" alt="GeGLU MLP 前向传播的性能轨迹,CPU 时间线上有五组被框出的事件,分别标注为 linear、linear、gelu、mul、linear" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 7:GeGLU MLP 的性能轨迹</td> </tr> </tbody> </table> </div> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/occupancy-queries.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/4WfWrc6KU8TAFYCiVlJiMutVJwDC6PzJPX3oyRakEt8/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL29jY3VwYW5jeS1xdWVyaWVzLnBuZw" alt="线性投影轨迹中高亮的 occupancy query" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 8:线性投影 CPU 时间线中高亮的 occupancy query</td> </tr> </tbody> </table> </div> <p>图 7 说明我们的预判是正确的。每次 forward(一次 <code>mlp_fwd</code>)中,GPU 恰好运行 5 个内核。图 8 高亮了线性投影层 CPU 时间线中的「occupancy query(占用率查询)」。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center">算子</th> <th align="center">CPU 算子</th> <th align="center">GPU 内核</th> <th align="center">启动过程</th> </tr> </thead><tbody><tr> <td align="center"><code>gate_proj</code></td> <td align="center"><code>aten::linear</code></td> <td align="center"><code>ampere_bf16_s16816gemm_bf16_128x128_...</code></td> <td align="center">occupancy query + cudaLaunchKernel</td> </tr> <tr> <td align="center"><code>up_proj</code></td> <td align="center"><code>aten::linear</code></td> <td align="center"><code>ampere_bf16_s16816gemm_bf16_128x128_...</code></td> <td align="center">occupancy query + cudaLaunchKernel</td> </tr> <tr> <td align="center"><code>gelu</code></td> <td align="center"><code>aten::gelu</code></td> <td align="center"><code>vectorized_elementwise_kernel&lt;4, GeluCUDAKernelImpl...&gt;</code></td> <td align="center">cudaLaunchKernel</td> </tr> <tr> <td align="center"><code>h * u</code></td> <td align="center"><code>aten::mul</code></td> <td align="center"><code>vectorized_elementwise_kernel&lt;4, ...MulFunctor...&gt;</code></td> <td align="center">cudaLaunchKernel</td> </tr> <tr> <td align="center"><code>down_proj</code></td> <td align="center"><code>aten::linear</code></td> <td align="center"><code>ampere_bf16_s16816gemm_bf16_128x256_...</code></td> <td align="center">occupancy query + cudaLaunchKernel</td> </tr> </tbody> </table> </div> <p>三个 GEMM 在启动前都会额外调用一次 <code>cudaOccupancyMaxActiveBlocksPerMultiprocessor</code>。我们在第 1 部分有一节专门讨论过,<a href="https://huggingface.co/blog/torch-profiler#why-does-matmul-have-an-extra-cuda-runtime-call">可以在这里找到</a>。这是 cuBLAS 在确定网格尺寸。逐元素算子(GeLU 和 mul)则直接启动,没有 occupancy query。因此,「一个 linear」实际是 query + launch,而「一个逐元素算子」只是 launch。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/simple-mlp-table.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/61n_xm1OHrItWfWy97USX2AvHlA3csBtCM6JZ8Af_Co/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL3NpbXBsZS1tbHAtdGFibGUucG5n" alt="GeGLU MLP 的性能剖析表列出算子名称及其 CUDA 耗时,其中 aten::transpose 和 aten::as_strided 等元数据算子的 CUDA 耗时显示为 0.000us" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 9:表格显示某些算子不会启动内核</td> </tr> </tbody> </table> </div> <p><code>aten::t</code>、<code>aten::transpose</code>、<code>aten::reshape</code>、<code>aten::view</code>、<code>aten::as_strided</code> 和 <code>aten::_unsafe_view</code> 都不会启动内核。它们在表中显示 <code>0.000us</code> 的 CUDA 耗时(图 9),因为它们只是在 CPU 上重写张量元数据(形状和步长)。读者扫一眼表格,可能会看到每个 linear 周围有大约六个算子名,但其中只有一个(<code>mm</code>)真正到达 GPU。</p> <h3 class="relative group flex items-baseline"> <a id="为什么会有两类-gemm-内核?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%9C%89%E4%B8%A4%E7%B1%BB-gemm-%E5%86%85%E6%A0%B8%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么会有两类 GEMM 内核? </span> </h3> <p>MLP 会把 <code>[batch, seq, dim]</code> 展平成 <code>[batch * seq, dim]</code>,再进行 matmul。在命令行调用中,我们使用的 <code>batch</code> 是 64,<code>seq</code> 是 128,所以下面出现的 <code>8192</code> 来自 <code>batch * seq = 64 * 128</code>。</p> <p>从轨迹中可以看到:</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center">Linear</th> <th align="center"><code>aten::mm</code> 输入维度</th> <th align="center">M·K·N</th> <th align="center">cuBLAS 内核</th> <th align="center">平均 CUDA 耗时</th> </tr> </thead><tbody><tr> <td align="center"><code>gate_proj</code></td> <td align="center"><code>[8192,768] x [768,3072]</code></td> <td align="center"><code>8192·768·3072</code></td> <td align="center"><code>…128x128…stages_32x5_tn</code></td> <td align="center">0.19ms</td> </tr> <tr> <td align="center"><code>up_proj</code></td> <td align="center"><code>[8192,768] x [768,3072]</code></td> <td align="center"><code>8192·768·3072</code></td> <td align="center"><code>…128x128…stages_32x5_tn</code></td> <td align="center">0.19ms</td> </tr> <tr> <td align="center"><code>down_proj</code></td> <td align="center"><code>[8192,3072] x [3072,768]</code></td> <td align="center"><code>8192·3072·768</code></td> <td align="center"><code>…128x256…stages_64x3_tn</code></td> <td align="center">0.17ms</td> </tr> </tbody> </table> </div> <p>三个 GEMM 的 FLOP 数相同,都是 <code>2·8192·768·3072 ≈ 38.7 GFLOP</code>,但 <code>down_proj</code> 快约 <code>10%</code>。同样的计算量,不同的形状(<code>N=768</code> 而不是 <code>3072</code>),让 cuBLAS 选择了不同的 tile(<code>128×256</code>,并使用更深的 <code>stages_64x3</code> 流水线),从而在该形状下获得更好的复用。</p> <blockquote class="note"> <p>如果想深入学习 tiling,可以从<a href="https://alvinwan.com/how-to-tile-matrix-multiplication/" rel="nofollow">这份很好的资料</a>开始。</p> </blockquote> <p>这也正解释了为什么表中有两行 GEMM(图 9):<code>128x128</code> 那一行对应 gate+up,<code>128x256</code> 那一行对应 down。</p> <h3 class="relative group flex items-baseline"> <a id="torchcompile-会做什么?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#torchcompile-%E4%BC%9A%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> <code>torch.compile</code> 会做什么? </span> </h3> <p>在编译 <code>forward</code> 方法并查看可视化结果之前,我们再来做一次预判思考练习,想一想我们能从性能轨迹中观察到哪些现象。这是一项很有意思的实践,每当你自己做性能剖析时,都要反复采用这种思考方式。要始终基于自己的经验预判来分析,一旦发现实际情况和预想不符,就要停下来排查背后的原因。</p> <pre><code class="language-bash">uv run 03_simple_mlp.py --batch 64 --<span class="hljs-built_in">seq</span> 128 --dim 768 --hidden 3072 --compile uvx trace-util traces -b traces </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/simple-mlp-compile-trace.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/KIqMgtwxvCKtTpJ2xr12mGFIV4C_2lcIF4xvSer06_w/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL3NpbXBsZS1tbHAtY29tcGlsZS10cmFjZS5wbmc" alt="编译后的 GeGLU MLP 性能轨迹,CPU 时间线上显示三次 aten::mm 调用和一个融合 Triton 内核,分别标注为 mm、mm、fused、mm" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 10:编译后的 GeGLU MLP 性能轨迹</td> </tr> </tbody> </table> </div> <p>在 eager 模式下,每个 <code>nn.Linear</code> 都会展开成一串调度器算子(<code>aten::linear</code> → <code>aten::t</code> → <code>aten::transpose</code> → <code>aten::matmul</code> → <code>aten::reshape</code> → <code>aten::mm</code>)。这些是 ATen 在到达真正的 GEMM 之前会经过的高层包装。<code>torch.compile</code> 会移除这条链。</p> <p>编译后的图运行时,已经没有 linear、matmul、transpose 或 reshape,这些元数据算子都被折叠进 <code>mm</code> 的调用方式中。我们能看到三次裸露的 <code>aten::mm</code> 外部调用(图 10)。可以证明二者使用了同一个通用矩阵乘法(GEMM)内核的依据是:内核名与 eager 模式逐字节一致:gate 和 up 使用 <code>...128x128...stages_32x5_tn</code>,down 使用 <code>...128x256...stages_64x3_tn</code>。</p> <h3 class="relative group flex items-baseline"> <a id="融合后的-triton-内核" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E8%9E%8D%E5%90%88%E5%90%8E%E7%9A%84-triton-%E5%86%85%E6%A0%B8" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 融合后的 Triton 内核 </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/fused.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/KOECWtMBEK6LzNlDYvmFsagk1LyXLm0uTfOgmFbcMBE/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2Z1c2VkLnBuZw" alt="编译后的 MLP 轨迹,其中 CPU 时间线上的 triton_poi_fused__unsafe_view_gelu_mul_0 内核被框出,它替代了 eager 运行中的独立 gelu 与 mul 内核" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 11:融合后的 Triton 内核</td> </tr> </tbody> </table> </div> <p>这是整篇 compile 课程的重点。Eager 模式下的两个逐元素内核(GeLU 和 mul)再加上一个 reshape,被折叠成一个内核:<code>triton_poi_fused__unsafe_view_gelu_mul_0</code>(图 11)。我们来解析这个名称:</p> <ul> <li><code>triton</code>:由 Inductor 的 Triton 后端生成(不是 cuBLAS,也不是 ATen)。</li> <li><code>poi</code>:pointwise,逐元素操作(Inductor 将逐元素内核标记为 <code>poi</code>,规约标记为 <code>red</code>,持久规约标记为 <code>per</code>)。</li> <li><code>fused__unsafe_view_gelu_mul</code>:被合并的算子:<code>_unsafe_view</code>(reshape)、GeLU 和 mul。</li> <li><code>0</code>:该图中的唯一编号。</li> </ul> <p>为什么这是一次性能优化上的提升?在动态执行模式下,中间变量 <code>h = gelu(g)</code> 是一个尺寸为 <code>[8192, 3072]</code> 的完整 BF16 张量(大小约 50MB):GeLU 内核会先将该张量写入高带宽显存(HBM),随后乘法内核又需要立刻从显存中将其读取出来。而算子融合会把这份中间数据保存在寄存器中(寄存器位于芯片内部,相比高带宽显存访问延迟更低)。Triton 内核仅会读取一次张量<code>g</code>和<code>u</code>,完成<code>gelu(g) * u</code>的运算后,只将最终结果写入一次显存,省去了中间张量在全局显存中往返读写的一整套开销。</p> <h2 class="relative group flex items-baseline"> <a id="使用手工调优内核" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E4%BD%BF%E7%94%A8%E6%89%8B%E5%B7%A5%E8%B0%83%E4%BC%98%E5%86%85%E6%A0%B8" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用手工调优内核 </span> </h2> <p>到目前为止,我们一直让 PyTorch(eager)和编译器(<code>torch.compile</code>)来选择内核。现在换成一个由人工专家编写并手工调优的内核。我们使用 <code>LigerGEGLUMLP</code> 层,可以通过 <code>kernels</code> 库轻松从 <a href="https://huggingface.co/kernels/kernels-community/liger-kernels">Hugging Face Hub</a> 获取它。</p> <pre><code class="language-python"><span class="hljs-keyword">from</span> kernels <span class="hljs-keyword">import</span> get_kernel kernels_layers = get_kernel(<span class="hljs-string">"kernels-community/liger-kernels"</span>, version=<span class="hljs-number">1</span>).layers kernels_geglu_mlp = kernels_layers.LigerGEGLUMLP(Config()).to(device, dtype=torch.bfloat16).<span class="hljs-built_in">eval</span>() </code></pre> <p>完整脚本在这里:<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/03_kernels_mlp.py"><code>03_kernels_mlp.py</code></a>。</p> <pre><code class="language-bash">uv run 03_kernels_mlp.py --batch 64 --<span class="hljs-built_in">seq</span> 128 --dim 768 --hidden 3072 uvx trace-util traces -b traces </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/kernels-profile.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/ttW0U2lBcNqrs5s8n_6qpfYkDxGNch_d7bo5S4xPpx4/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2tlcm5lbHMtcHJvZmlsZS5wbmc" alt="LigerGEGLUMLP 前向传播的性能轨迹,CPU 时间线上显示三个 aten::linear 组和一个 LigerGELUMulFunction 组" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 12:<code>LigerGEGLUMLP</code> 层的性能轨迹</td> </tr> </tbody> </table> </div> <p>图 12 展示了使用 Hub 上 Liger kernels 的 <code>LigerGEGLUMLP</code> 层性能轨迹。</p> <h3 class="relative group flex items-baseline"> <a id="为什么使用-kernels-库" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8-kernels-%E5%BA%93" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么使用 kernels 库 </span> </h3> <p>用 Triton 或 CUDA 编写内核是一回事,<em>分发</em> 它们又是另一回事。内核必须针对 GPU 架构、CUDA 版本和 PyTorch 版本的精确组合进行编译。通常出问题的就是这一步(「在我机器上能跑」、缺少 <code>nvcc</code>、Triton 版本不对)。</p> <p><a href="https://github.com/huggingface/kernels" rel="nofollow"><code>kernels</code></a> 库会把构建步骤从本机移走。<code>get_kernel("kernels-community/liger-kernels", version=1)</code> 会从 Hugging Face Hub 下载一个<strong>预构建、版本固定</strong>的内核包,并缓存在本地(这里位于 <code>~/.cache/...kernels-community--liger-kernels</code>)。它的好处包括:</p> <ul> <li>内核在 CI 中一次性为多种架构和版本组合编译完成。开发者下载正确的二进制即可,而不用自己编译。</li> <li><code>version=1</code> 固定了精确构建,因此运行脚本的所有人都会拿到同一个内核。不会出现「我更新了某个包之后它变慢了」。</li> <li>该包暴露了一个 <code>.layers</code> 属性,里面是可直接替换的 <code>nn.Module</code>(例如 <code>LigerGEGLUMLP</code>)。把自己的模块换成它们即可,模型其他部分不需要改变。</li> </ul> <h3 class="relative group flex items-baseline"> <a id="调优内核为什么更好" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E8%B0%83%E4%BC%98%E5%86%85%E6%A0%B8%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9B%B4%E5%A5%BD" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 调优内核为什么更好 </span> </h3> <p>这里说的「调优」包含两个具体含义,而且两者都能在轨迹里看到。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/compile-preops.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/AMsGmt7pP3OopRQkS6t16UC7vIeRCB79_6AGKSeqiRM/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL2NvbXBpbGUtcHJlb3BzLnBuZw" alt="编译后的 MLP 轨迹中,在编译图运行前,CPU 时间线上的 TorchDynamo、prologue 和 guard 前置操作被框出" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 13:编译运行在任何 GEMM 执行前都要付出前置操作开销(Dynamo、guard、prologue)</td> </tr> </tbody> </table> </div> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-mlp-fusion/no-preops.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/7cRQEOcaX-zml6YwddKDmh4xZJ9nfGn9kP5GDgBwnUg/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1tbHAtZnVzaW9uL25vLXByZW9wcy5wbmc" alt="LigerGEGLUMLP 轨迹中,原本 compile 前置操作所在的位置是空的,显示手写内核没有 Dynamo 或 guard 开销" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 14:Liger 内核没有前置操作,原本可能出现这些操作的框中是空的</td> </tr> </tbody> </table> </div> <ol> <li><p><strong>融合已经内置其中。</strong> <a href="https://huggingface.co/kernels/kernels-community/liger-kernels/blob/v1/build/torch-cuda/layers.py#L307"><code>LigerGEGLUMLP</code></a> 的 forward 是 <code>down_proj(LigerGELUMulFunction.apply(gate_proj(x), up_proj(x)))</code>。<a href="https://huggingface.co/kernels/kernels-community/liger-kernels/blob/v1/build/torch-cuda/geglu.py#L130"><code>LigerGELUMulFunction</code></a> 会运行一个 Triton 内核 <a href="https://huggingface.co/kernels/kernels-community/liger-kernels/blob/v1/build/torch-cuda/geglu.py#L97"><code>_geglu_tanh_forward_kernel</code></a>,一次完成 <code>gelu(gate) * up</code>。这与我们从 <code>torch.compile</code> 中看到的效果完全一致:中间结果不会通过 HBM 往返。这里<strong>不需要编译器</strong>就能做到,如图 13 和图 14 所示(没有 Dynamo guard、没有编译延迟,也没有重新编译风险)。</p> </li> <li><p><strong>启动参数是为硬件选好的。</strong> 内核不会随机猜测 block size。Liger 的 <a href="https://huggingface.co/kernels/kernels-community/liger-kernels/blob/v1/build/torch-cuda/geglu.py#L95"><code>calculate_settings</code></a> 会根据列数选择这些参数。</p> </li> </ol> <p>这里需要诚实看待取舍,因为原始数字可能产生误导。Liger 内核运行耗时为 <strong>92.8 µs</strong>,而 compile 运行中 Inductor 的融合内核是 <strong>89.4 µs</strong>。乍看之下,手写内核略慢,但这种比较掩盖了让它有价值的成本差异。</p> <p><code>torch.compile</code> 会针对<strong>静态形状</strong>做专门化。Inductor 的 <code>89.4 µs</code> 内核之所以快,正是因为它是为 <em>这个精确的</em> <code>[8192, 3072]</code> 问题生成的。一旦改变 batch size、sequence length 或 hidden dimension,Dynamo 就会重新追踪,并再次支付编译成本,换取一个新的专门化内核。</p> <p>因此,实际要做的取舍并非 “手写低效内核” 与 “编译后高效内核” 二选一,而是<strong>在通用型高性能内核和针对单一输入形状深度定制的专用内核之间做选择</strong>。Liger 内核只需一组启动参数,无需重新编译即可适配任意张量形状运行。它牺牲掉按不同形状定制优化所能省下的几微秒极致耗时,换来对动态变化张量形状的强兼容性。</p> <h2 class="relative group flex items-baseline"> <a id="结论" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-mlp-fusion#%E7%BB%93%E8%AE%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 结论 </span> </h2> <p>下表汇总了每一步改变了 GPU 上的什么,又保留了什么。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">设置</th> <th align="left">发生了什么变化</th> <th align="left">什么保持不变</th> </tr> </thead><tbody><tr> <td align="left">Eager <code>nn.Linear</code></td> <td align="left">基线:偏置加法已经被折叠进 GEMM epilogue(<code>addmm</code>),所以它是 <em>一个</em> cuBLAS 内核,而不是 matmul 再加 add</td> <td align="left">—</td> </tr> <tr> <td align="left">编译后的 <code>nn.Linear</code></td> <td align="left">少量 CPU 调度算子(<code>aten::t</code> 视图 bookkeeping)消失</td> <td align="left">仍是同一个 cuBLAS GEMM 内核,逐字节一致。Compile 没有可融合的内容</td> </tr> <tr> <td align="left">Eager MLP</td> <td align="left">5 个 GPU 内核:3 个 GEMM + 一个 GeLU + 一个 mul。<code>[8192, 3072]</code> 中间结果完整往返 HBM</td> <td align="left">每个 GEMM 仍是独立 linear 使用的同一类无偏置 cuBLAS 内核</td> </tr> <tr> <td align="left">编译后的 MLP</td> <td align="left">GeLU + mul + reshape 折叠成<strong>一个</strong>融合 Triton 内核;中间结果留在寄存器中。需要支付 compile 前置操作开销(Dynamo、guard)</td> <td align="left">3 个 GEMM 未受影响,cuBLAS 内核名完全相同</td> </tr> <tr> <td align="left">Liger MLP</td> <td align="left">同样完成融合,但融合内置在手写 Triton 内核中,并使用硬件调优后的启动参数,且<strong>没有</strong> Dynamo、guard 或编译延迟</td> <td align="left">3 个 GEMM 仍是同一批 cuBLAS 内核</td> </tr> </tbody> </table> </div> <p>如果说有一个习惯值得坚持下去,那就是我们在每次查看轨迹前练习的那个:<strong>先猜,再看。</strong> 先说明你预估这份追踪日志会包含哪些内容,再打开日志文件;一旦发现实际内容和你的预判不符,就把这些偏差当作屏幕上最值得研究的亮点。</p> <p>这是 <strong>PyTorch 性能剖析</strong> 系列的第二站。下一篇文章,我们将继续循序渐进地深入讲解,从当前的多层感知器模块过渡到注意力模块,最终完整介绍整个模型。</p> <p>感谢 <a href="https://huggingface.co/NoeFlandre">Noe Flandre</a> 和 <a href="https://huggingface.co/pedrogengo">Pedro Gabriel Gengo Lourenço</a> 审阅本文初稿!</p>

2026/6/11
阅读更多

PyTorch 性能剖析(第 1 部分):torch.profiler 入门指南

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/torch-profiler.md">在 GitHub 上更新</a></div> <p></p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/thumbnail.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/XcjKmKlSc6v7VpgcXumUg4Llz2AqJubhOeaYDM4pD2o/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci90aHVtYm5haWwucG5n" alt="博客文章缩略图" referrerpolicy="no-referrer"></a><p></p> <blockquote> <p><em>无法进行性能剖析( profiling ),就无法优化。</em></p> </blockquote> <p>无论目标是让大语言模型(LLM)每秒生成更多词元(token)、把推理耗时缩短几毫秒,还是弄清楚训练循环为什么比规格表承诺的速度慢,最终都绕不开性能剖析。</p> <p>难点在于,性能剖析的入门门槛很高。性能轨迹像一面密密麻麻的彩色矩形墙,各类事件名称也常常让人望而生畏。大多数教程默认读者已经知道如何阅读轨迹。因此,即便已经知道应该做性能剖析,打开一份轨迹也常常像是一件可以留到以后、或交给别人处理的麻烦事。本文以及这个系列,正是为了降低这道门槛。</p> <p>本文是《PyTorch 性能剖析》系列的开篇文章。本系列会循序渐进地介绍如何阅读性能轨迹,并把这些观察用于指导优化。计划如下:</p> <ol> <li><strong>第 1 部分(本文):</strong> 从最简单的操作开始:一次矩阵乘法后接偏置加法,学习如何阅读 <code>torch.profiler</code> 返回的结果。</li> <li><strong>第 2 部分:</strong> 扩展到 <code>nn.Linear</code> 和一个小型多层感知机(MLP),借助轨迹数据找准优化方向,并初步查看底层 CUDA 内核。</li> <li><strong>第 3 部分:</strong> 结合 <code>transformers</code> 库,在大语言模型上综合运用前述全部知识。</li> </ol> <p>本文从初学者视角记录这段过程。除基础 PyTorch 知识外,不需要其他前置知识;可以把它当作一篇轻松阅读的教程,过程中会穿插一些「原来如此」的瞬间。文章采用<strong>问题导向</strong>结构:打开一份轨迹,提出「等等,为什么会这样?」这样的问题,再顺着线索追到答案。读完本文后,应能理解以下内容:</p> <ul> <li>如何设置 <code>torch.profiler</code>,以及该工具的输出数据含义;</li> <li>读懂性能统计表与性能轨迹(CPU 时间线、GPU 时间线,以及两者间反常的空闲间隔);</li> <li>从 Python 接口调用,逐层下沉至 CUDA 内核执行的完整事件链路;</li> <li>启用 <code>torch.compile</code> 后,哪些性能指标会变化,更关键的是:<strong>哪些指标保持不变</strong>。</li> </ul> <p>开始之前,先明确两个关键定义,方便后续阅读:</p> <ol> <li><strong>GPU 内核(kernel)</strong>:能够依托 GPU 海量线程并行运行的程序单元。</li> <li><strong>CPU 负责调度并启动各类 GPU 内核</strong>。</li> </ol> <p>日常开发一般无需手动编写 GPU 内核:调用 PyTorch 算子时,框架会自动将运算转化为一个或多个 GPU 内核,在显卡上完成计算。</p> <p>掌握以上两个概念,我们就开始逐一探究问题。</p> <blockquote class="note"> <p>本文使用的完整脚本在这里:<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py"><code>01_matmul_add.py</code></a>。建议在单独的标签页中打开脚本,并逐步阅读代码。本文使用 <code>NVIDIA A100-SXM4-80GB</code> GPU 运行这些脚本。</p> </blockquote> <h2 class="relative group flex items-baseline"> <a id="矩阵乘法与加法运算" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E4%B8%8E%E5%8A%A0%E6%B3%95%E8%BF%90%E7%AE%97" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 矩阵乘法与加法运算 </span> </h2> <p>正如 <a href="https://youtu.be/7knwihgj0fU?si=uvzGH-J9bsCHP4Nn&amp;t=2199" rel="nofollow">Sara Hooker 博士的准确调侃</a>:人主要由水构成,而深度神经网络主要由矩阵乘法构成。矩阵乘法是深度学习的基石,用它作为性能剖析之旅的起点再合适不过。</p> <pre><code class="language-py"><span class="hljs-keyword">def</span> <span class="hljs-title function_">fn</span>(<span class="hljs-params">x, w, b</span>): <span class="hljs-keyword">return</span> torch.add(torch.matmul(x, w), b) </code></pre> <blockquote> <p>矩阵乘法搭配偏置加法,模拟了神经元中权重与偏置的交互方式。顺带一提,这里的加法也会帮助我们理解 <a href="https://huggingface.co/blog/zh/torch-profiler#lets-see-some-torch-compile-at-work" rel="nofollow">后文</a> 中的编译机制。</p> </blockquote> <p>我们将借助 <code>torch.profiler</code> 模块完成性能剖析,整体分为四步:</p> <ol> <li>准备好 <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L26-L27">需要剖析的代码</a>(这里是 <code>def fn</code>,它封装了矩阵乘法和偏置加法)。</li> <li><a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L32">标注算法</a>。这个步骤完全可选,但建议执行。<code>record_function</code> 会把函数标注为 <code>matmul_add</code>,后续在性能轨迹中可以快速定位对应模块。</li> </ol> <pre><code class="language-py"><span class="hljs-keyword">def</span> <span class="hljs-title function_">step</span>(): <span class="hljs-keyword">with</span> torch.profiler.record_function(<span class="hljs-string">"matmul_add"</span>): <span class="hljs-keyword">return</span> fn(x, w, b) </code></pre> <ol start="3"> <li>用 <code>torch.profiler.profile</code> <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L53-L62">上下文管理器</a> 包裹代码。</li> </ol> <pre><code class="language-py"> <span class="hljs-keyword">with</span> torch.profiler.profile( activities=[ torch.profiler.ProfilerActivity.CPU, <span class="hljs-comment"># the cpu activities</span> torch.profiler.ProfilerActivity.CUDA, <span class="hljs-comment"># the gpu activities</span> ], ) <span class="hljs-keyword">as</span> prof: <span class="hljs-comment"># it is recommended to run events multiple times to warm up the GPUs</span> <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>): step() prof.step() </code></pre> <ol start="4"> <li>导出 <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L70">剖析结果</a>。</li> </ol> <pre><code class="language-py"><span class="hljs-comment"># the profiler table</span> prof.key_averages().table(sort_by=<span class="hljs-string">"cuda_time_total"</span>, row_limit=<span class="hljs-number">15</span>) <span class="hljs-comment"># the profiler trace</span> prof.export_chrome_trace(trace_path) </code></pre> <p>剖析器会导出两类不同产物:</p> <ol> <li>性能统计表:提供算法的统计摘要,用来回答「什么耗时最多」。这对定位性能热点很有帮助。热点可能是最耗时的事件,也可能是流水线瓶颈,或是触发次数特别多的事件。</li> <li>性能轨迹:提供时间维度上的执行视图,用来回答「某个操作何时发生、为什么发生」,并展示 CPU 与 GPU 上发生的活动。当需要调查启动了哪些内核、内核启动是否延迟、CPU 与 GPU 活动是否重叠时,它很有用。</li> </ol> <p>现在通过第一次执行看看这两者如何工作。(<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py">完整源码 <code>01_matmul_add.py</code> 在这里</a>)</p> <blockquote class="note"> <p>建议在搭载 GPU 的设备上运行该脚本。</p> </blockquote> <pre><code class="language-bash">uv run 01_matmul_add.py --size 64 </code></pre> <p>在搭载 GPU 的机器上运行上述脚本后,会生成 <code>traces/01_matmul_add</code> 文件夹,里面包含两类分析结果文件:</p> <pre><code class="language-bash">64_bf16_cold_eager.json 64_bf16_cold_eager.txt </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/profile-table-64.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/b1CduYXS7R6ldqh4Emltrrb-RRfTvM0ON8uugA66Zvo/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9wcm9maWxlLXRhYmxlLTY0LnBuZw" alt="64×64 矩阵上 matmul add 的性能统计表" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 1:64×64 矩阵乘加运算的性能统计表</td> </tr> </tbody> </table> </div> <p><code>.txt</code> 文件存放性能剖析汇总表。打开文件后(如图 1),可以看到一张大型表格:首列是剖析区间内执行的各类事件名称。</p> <p>其余各列记录对应事件在 CPU、GPU,或 <code>torch.profiler.profile</code> 的 <code>activities</code> 参数指定设备上的耗时。重点观察耗时占比最高的事件,并结合业务逻辑判断该耗时是否合理;同时也要关注 <code># of Calls</code> 这一列,它表示对应事件的触发频次。</p> <p>顺便说明一下自身耗时「Self CPU/CUDA」与总耗时「CPU/CUDA total」的区别。「Self」列只统计事件自身花费的时间,<strong>不含内部子事件耗时</strong>。「total」列则包含事件自身及其所有嵌套子事件的耗时总和。因此,查看 <code>matmul_add</code> 的「CPU total」时,它包含自身耗时,以及它触发的所有内部子算子的 CPU 耗时。这是一个需要注意的重要细节。</p> <p>如果查看表格最后两行,会发现剖析器给出:</p> <pre><code class="language-bash">Self CPU time total: 2.314ms Self CUDA time total: 23.104us </code></pre> <p>CPU 耗时单位是 <code>ms</code>,而 GPU 耗时单位是 <code>us</code>。为了建立直观感受:GPU 上花费的时间(内核 <code>ampere_bf16_s16816gemm...</code>)不到 CPU 上花费时间(<code>matmul_add</code> 操作)的 1%。GPU 大部分时间处于空闲状态,这是一个明显的警示信号。出现这种情况的原因是,小规模矩阵乘法在 GPU 上运算极快,程序绝大部分开销都消耗在内核准备、GPU 任务启动、发送待乘数据和收集结果等环节。这类受调度开销制约的算法被称作 <em>开销受限型(overhead-bound)</em> 算法。</p> <p>脱离这种状态最简单的方法,是<strong>改用更大尺寸的矩阵执行乘法运算</strong>。</p> <pre><code class="language-bash">uv run 01_matmul_add.py --size 4096 </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/profiler-table-4096.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/QLylmHcvxxrXU1PL5tdLZ4nBiDAGccEPS5XGgLzCb80/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9wcm9maWxlci10YWJsZS00MDk2LnBuZw" alt="4096×4096 矩阵上 matmul add 算法的性能统计表" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 2:4096×4096 矩阵上 matmul add 的性能统计表</td> </tr> </tbody> </table> </div> <p>图 2 最后两行是:</p> <pre><code class="language-bash">Self CPU time total: 4.908ms Self CUDA time total: 4.495ms </code></pre> <p>两项耗时单位均为毫秒,可见仅通过增大矩阵尺寸,就能让 GPU 承担更多实际计算。对照图 2 能发现:如今绝大部分 CUDA 耗时消耗在 GPU 内核(<code>ampere_bf16_s16816gemm_..</code>)上,而非发起内核调用的 CPU 操作(<code>matmul_add</code>)。这说明程序成功从<strong>开销受限型(overhead-bound)</strong>转为<strong>计算受限型(compute-bound)</strong>。</p> <p>接下来通过 <code>.json</code> 结果文件可视化任务下发调用链。可以将 JSON 文件上传至 <a href="https://ui.perfetto.dev/" rel="nofollow">Perfetto UI</a> 查看性能轨迹,也可以执行命令 <code>uvx trace-util traces -b traces</code> 直接生成 Perfetto 访问链接。</p> <h2 class="relative group flex items-baseline"> <a id="64×64-性能轨迹" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#64%C3%9764-%E6%80%A7%E8%83%BD%E8%BD%A8%E8%BF%B9" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 64×64 性能轨迹 </span> </h2> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/64-matmul-add.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/ovCjx7prGTFHTXo_yDq2Wk7vMpkWt6IO_011-Cv3ZHM/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci82NC1tYXRtdWwtYWRkLnBuZw" alt="CUDA GPU 上 64×64 bf16 矩阵乘法后接加法的 PyTorch 性能轨迹" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 3:64×64 矩阵上 matmul 和 add 的性能轨迹</td> </tr> </tbody> </table> </div> <p>在图 3 中,我们能看到矩阵乘加运算的性能剖析时序轨迹。矩形条的宽度代表事件持续时长,纵向嵌套结构代表调用层级;CPU 时间线展示 CPU 侧发生的各类事件,GPU 时间线则呈现 GPU 内核的实际执行过程。图中空白区间代表等待或硬件空闲时段。</p> <p>脚本采用如下默认配置运行:</p> <ul> <li>矩阵尺寸 64:输入、权重与偏置张量形状均为 (64, 64)</li> <li>数据类型 bf16:采用 bfloat16(16 位脑浮点)精度</li> <li>未开启编译:没有编译 <code>torch</code> 算子</li> <li>无预热:性能采集前未做 GPU 预热</li> </ul> <blockquote> <p>使用 Perfetto 工具时,推荐快捷键操作来快速浏览时序图:W/A/S/D 按键控制视图移动缩放。</p> </blockquote> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/gpu-cpu-trace.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/ZNUGacJwdtn0oPMqC5-TR3DahTIskWuFyQuRly2IUDg/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9ncHUtY3B1LXRyYWNlLnBuZw" alt="Perfetto 中并排标注 CPU 时间线和 GPU 时间线的 PyTorch 性能轨迹" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 4:PyTorch 性能轨迹中的 CPU 时间线和 GPU 时间线</td> </tr> </tbody> </table> </div> <p>图 4 包含两条时序泳道,分别对应 CPU 行为与 GPU 行为。CPU 时间线里能看到三段剖析采集周期(从 <code>ProfilerStep#2</code> 开始),该配置由采样调度器决定:</p> <pre><code class="language-py">schedule = torch.profiler.schedule(wait=<span class="hljs-number">1</span>, warmup=<span class="hljs-number">1</span>, active=<span class="hljs-number">3</span>, repeat=<span class="hljs-number">1</span>) </code></pre> <p><code>wait</code> 参数:跳过干扰数据较多的初始化阶段(对应 <code>ProfilerStep#0</code>),</p> <p><code>warmup</code> 参数:程序预热运行,但剖析器不采集日志(对应 <code>ProfilerStep#1</code>),</p> <p><code>active</code> 参数:正式采集、最终体现在时序图中的运行轮次。调度配置可以在 <a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L58">这段脚本</a> 中找到。</p> <p>接下来围绕时序图展开排查。</p> <h3 class="relative group flex items-baseline"> <a id="为什么-profilerstep2-耗时这么长?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E4%B8%BA%E4%BB%80%E4%B9%88-profilerstep2-%E8%80%97%E6%97%B6%E8%BF%99%E4%B9%88%E9%95%BF%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么 ProfilerStep#2 耗时这么长? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/why-is-step-2-big.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/lw84urVa5AVk0GgylgH20Sf8YDn6WZtFTHPmri2Qo2A/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci93aHktaXMtc3RlcC0yLWJpZy5wbmc" alt="PyTorch 性能轨迹中 ProfileStep#2 看起来比 ProfileStep#3 和 ProfileStep#4 更宽" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 5:<code>ProfileStep#2</code> 的矩形宽度显著大于后续轮次</td> </tr> </tbody> </table> </div> <p>图 5 中可以看到,<code>ProfileStep#2</code> 耗时远超后续轮次。仔细观察后,会发现自定义标记 <code>matmul_add</code> 也呈现相同规律。<strong>问题根源藏在标记内部的子事件中,而非标记本身</strong>。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center">Step</th> <th align="center"><code>matmul_add</code> start</th> <th align="center"><code>aten::matmul</code> start</th> <th align="center">gap</th> </tr> </thead><tbody><tr> <td align="center">#2</td> <td align="center">138.736</td> <td align="center">366.493</td> <td align="center">227.757 µs</td> </tr> <tr> <td align="center">#3</td> <td align="center">517.926</td> <td align="center">523.447</td> <td align="center">5.521 µs</td> </tr> <tr> <td align="center">#4</td> <td align="center">610.039</td> <td align="center">614.527</td> <td align="center">4.488 µs</td> </tr> </tbody> </table> </div> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/gap-227.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/ypmEShTJKMazjmsNu3RSczjxCJST5Idl6fx_QrVbK8M/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9nYXAtMjI3LnBuZw" alt="ProfileStep#2 中 record_function matmul_add 和 aten::matmul 下发之间存在 228 微秒间隔" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 6:<code>record_function("matmul_add")</code> 和 <code>aten::matmul</code> 之间约 228 微秒的空窗期</td> </tr> </tbody> </table> </div> <p>图 6 中标注的约 228 微秒,是从进入 <code>record_function("matmul_add")</code> 代码块,到 PyTorch 真正下发 <code>aten::matmul</code> 算子之间的<strong>空窗期</strong>。造成这段耗时的诱因有很多:临时显存工作区申请、<a href="https://developer.nvidia.com/cublas" rel="nofollow">cuBLAS</a>(NVIDIA 专有的 GPU 加速基础线性代数库)内部启发式策略开销,或是动态懒加载模块。对此可以先暂时跳过,也可以遵循通用做法:<a href="https://huggingface.co/datasets/ariG23498/profiling-pytorch/blob/main/01_matmul_add.py#L35-L39">在性能采集前补充多轮预热运行</a>。</p> <p>在性能剖析场景里,预热指正式采样前预先反复执行目标算子。上文提到的各类 GPU 初始化工作仅会执行一次,不应把这类一次性开销纳入剖析统计。本示例包含两级预热:一是开启剖析器之前手动循环运行函数;二是依托剖析器配置里的 <code>warmup</code> 参数,在剖析周期内部完成预热。本段代码已启用循环运行和采样调度配置。</p> <pre><code class="language-bash">uv run 01_matmul_add.py --warmup </code></pre> <p><a href="https://ui.perfetto.dev/#!/?url=https://huggingface.co/buckets/ariG23498/traces/resolve/01_matmul_add/64_bf16_warm_eager.json" rel="nofollow">经过预热、64×64 矩阵的 Perfetto 性能轨迹</a></p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/warmup.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/oFPnUKKT9WN5CFI3d3BkwiGd5qfpSpxUKxWgtGuk1Pc/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci93YXJtdXAucG5n" alt="预热步骤之后的 PyTorch 性能轨迹,ProfileStep#2 不再显示冷启动开销" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 7:完成预热后,所有剖析轮次耗时趋于一致</td> </tr> </tbody> </table> </div> <p>从图 7 能够看出,各轮剖析任务耗时基本持平,但这不代表一次性初始化开销已经被优化掉;预热只是让这类开销避开了性能采样。关于如何进一步缩减内核启动开销,可以继续阅读这篇 <a href="https://pytorch.org/blog/accelerating-generative-ai-2/" rel="nofollow">文章</a>。</p> <h3 class="relative group flex items-baseline"> <a id="为什么-cpu-时序泳道和-gpu-时序泳道存在约-25-毫秒的时间差?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E4%B8%BA%E4%BB%80%E4%B9%88-cpu-%E6%97%B6%E5%BA%8F%E6%B3%B3%E9%81%93%E5%92%8C-gpu-%E6%97%B6%E5%BA%8F%E6%B3%B3%E9%81%93%E5%AD%98%E5%9C%A8%E7%BA%A6-25-%E6%AF%AB%E7%A7%92%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么 CPU 时序泳道和 GPU 时序泳道存在约 2.5 毫秒的时间差? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/gap-bw-kernel-launch.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/gNhMKp5K9iAoWzvm5i5ANR4P8WvkcJanh3FzvIk7rWs/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9nYXAtYncta2VybmVsLWxhdW5jaC5wbmc" alt="PyTorch 性能轨迹中 CPU 时间线和 GPU 时间线之间存在 2.32 毫秒偏移" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 8:CPU 与 GPU 时间线之间存在约 2.5 ms 启动延迟</td> </tr> </tbody> </table> </div> <p>图 8 显示 CPU 和 GPU 时间线之间约有 2.5 ms 的偏移:CPU 提交 CUDA 内核之后,GPU 真正开始执行之前会有一段延迟。直觉上,预热阶段加上调度器的 <code>wait</code> 和 <code>warmup</code> 应该能让 GPU 保持忙碌,并缩小这个偏移。</p> <p>为探明真实原因,我们小幅修改采样调度参数:</p> <pre><code class="language-diff"><span class="hljs-deletion">- schedule = torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=1)</span> <span class="hljs-addition">+ schedule = torch.profiler.schedule(wait=0, warmup=0, active=3, repeat=1)</span> </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/full-profile.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/Rj1h1oQ9k9jN3V-LPWdlQ6apSFb-kFrKnoiVL8psk3M/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9mdWxsLXByb2ZpbGUucG5n" alt="wait=0 warmup=0 时的 PyTorch 性能轨迹,在步骤之间显示 Activity Buffer Request" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 9:设置<code>wait=0</code> 和 <code>warmup=0</code> 后,轨迹中出现 Activity Buffer Request 事件</td> </tr> </tbody> </table> </div> <p>图 9 显示,所有 GPU 运算开始前,GPU 时间线里出现了一项 <code>Activity Buffer Request</code>(活动缓冲区申请)事件,接下来我们放大视图细看细节。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/mat-add-gap.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/Gdm7vzIyfgtZHYeA-yD3ZJL_Vbo5gCFgm-ze6BLAcRc/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9tYXQtYWRkLWdhcC5wbmc" alt="剖析器缓冲区申请导致 matmul 和 add CUDA 内核之间出现间隔" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 10:第 1 轮采样周期中,矩阵乘内核与加法内核之间出现一段时间空隙</td> </tr> </tbody> </table> </div> <p>放大 GPU 时序轨迹后能够发现:<code>ProfileStep#0</code> 对应的矩阵乘法和加法内核是连续串行执行的(该轮 CPU 时序未在图中展示),而 <code>ProfileStep#1</code> 的两个内核中间多出一段空窗。最合理的解释是<strong>缓冲区溢出</strong>,在内核运行途中触发了一次新的缓冲区申请(向 GPU 显存申请分配内存)。</p> <p>想要排除其他诱因,最稳妥的办法是增加采样迭代次数进行观察:修改参数 <code>active=20</code>,重新采集性能数据。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/20-iters.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/Oy6au6Q1C4GZcSfzfvEpX8HbFKTqydna4QF9mfgFVmI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci8yMC1pdGVycy5wbmc" alt="20 个 active 迭代的 PyTorch 性能轨迹,确认缓冲区申请导致的间隔只出现一次" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 11:20 轮有效采样结果,空隙仅单次出现,证实由缓冲区申请导致</td> </tr> </tbody> </table> </div> <p>如图 11 所示,仅在 <code>ProfileStep#1</code> 出现该空隙,和之前推断吻合,因此可以确定空档源自缓冲区内存申请。</p> <h3 class="relative group flex items-baseline"> <a id="事件链" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E4%BA%8B%E4%BB%B6%E9%93%BE" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 事件链 </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/cpu-nests.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/by5hLQ1n23pvXDE6OIQXqNF1_9LAjnXulrEsCG8iEx4/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9jcHUtbmVzdHMucG5n" alt="PyTorch 剖析器中嵌套的 CPU 下发调用链:ProfileStep、matmul_add、aten::matmul、aten::mm" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 12:PyTorch 剖析图中嵌套式 CPU 下发调用链:ProfileStep → matmul_add → aten::matmul → aten::mm</td> </tr> </tbody> </table> </div> <p>图 12 展示了层层嵌套的 CPU 调用栈,是理解算子下发全链路的关键视图。</p> <p>最外层的 <code>ProfileStep#编号</code> 包裹整轮性能采样逻辑;因为代码里手动添加了标注,视图里出现 <code>matmul_add</code> 节点,其内部包含两次 ATen 算子调用:矩阵乘法和矩阵加法。</p> <p>面向用户的 PyTorch 矩阵乘法调用最终会落到 <a href="https://github.com/pytorch/pytorch/tree/main/aten/src/ATen" rel="nofollow">ATen 层</a> 的 <code>aten::matmul</code> 调度接口。<code>aten::mm</code> 是专用于二维矩阵相乘的底层后端算子。</p> <p>补充一个有趣细节:若给张量新增批量维度(batch 轴),PyTorch 会自动选用批量矩阵乘算子 <code>aten::bmm</code>。下面顺带切换样例,观察 <code>aten::bmm</code> 的实际调用表现。</p> <pre><code class="language-diff"><span class="hljs-deletion">- x = torch.randn(args.size, args.size, device=device, dtype=dtype)</span> <span class="hljs-deletion">- w = torch.randn( args.size, args.size, device=device, dtype=dtype)</span> <span class="hljs-deletion">- b = torch.randn(args.size, args.size, device=device, dtype=dtype)</span> <span class="hljs-addition">+ # adding a batch size of 8</span> <span class="hljs-addition">+ x = torch.randn(8, args.size, args.size, device=device, dtype=dtype)</span> <span class="hljs-addition">+ w = torch.randn(8, args.size, args.size, device=device, dtype=dtype)</span> <span class="hljs-addition">+ b = torch.randn(8, args.size, args.size, device=device, dtype=dtype)</span> </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/bmm.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/p-JkJls5mEenes4eYirbOBnD7WReGL35lOGyz2czAok/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9ibW0ucG5n" alt="PyTorch 性能轨迹显示 aten::matmul 针对 3D 批量张量下发 aten::bmm" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 13:批量矩阵乘法(BMM 运算)</td> </tr> </tbody> </table> </div> <p>在图 13 中,给输入张量新增批量维度后,<code>aten::matmul</code> 内部不再调用 <code>aten::mm</code>,转而使用 <code>aten::bmm</code>,同时还附带一系列前置 CUDA 运行时调用。这也侧面体现出 cuBLAS 会依靠内部启发式逻辑,为当前运算择优调度最合适的 GPU 内核。</p> <blockquote> <p>后文若无特殊说明,我们均采用普通二维矩阵开展实验。</p> </blockquote> <h3 class="relative group flex items-baseline"> <a id="为什么矩阵乘法会多出一项-cuda-运行时调用?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E4%B8%BA%E4%BB%80%E4%B9%88%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E4%BC%9A%E5%A4%9A%E5%87%BA%E4%B8%80%E9%A1%B9-cuda-%E8%BF%90%E8%A1%8C%E6%97%B6%E8%B0%83%E7%94%A8%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么矩阵乘法会多出一项 CUDA 运行时调用? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/cudaoccupancy.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/v8YZPM-_VBMx9oud_mGTokg3sHiwht5HyH-GOOH_mJw/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9jdWRhb2NjdXBhbmN5LnBuZw" alt="CPU 时间线显示 cudaOccupancyMaxActiveBlocksPerMultiprocessor 位于 matmul cudaLaunchKernel 之前" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 14:矩阵乘法内核启动前执行了 cudaOccupancyMaxActiveBlocksPerMultiprocessor 查询</td> </tr> </tbody> </table> </div> <p>可以观察到:<code>aten::mm</code> 对应两次 CUDA Runtime 调用,分别是图中标注的 <code>cudaOccupancyMaxActiveBlocksPerMultiprocessor</code> 与 <code>cudaLaunchKernel</code>;而 <code>aten::add</code> 仅存在 <code>cudaLaunchKernel</code> 一次调用。</p> <p><code>cudaOccupancyMaxActiveBlocksPerMultiprocessor</code> 是 CPU 侧的资源预规划接口,作用为:<strong>给定内核函数、线程块尺寸与动态共享内存大小,查询单个流式多处理器(SM)最多能同时容纳多少个该内核的线程块</strong>。</p> <p>由此产生疑问:为何矩阵乘法需要资源预规划,加法运算却不需要?</p> <p>答案取决于内核的硬件资源占用。点击时序图里的 GPU 内核条目,即可查看对应内核的资源开销详情。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/matmul-footprint.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/yE-a-cE1Gm6PYpVbeyn0bMcqvJQcbX5BjCdldmsxc38/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9tYXRtdWwtZm9vdHByaW50LnBuZw" alt="cuBLAS 矩阵乘内核资源占用:Perfetto 中的寄存器、共享内存和线程块尺寸" referrerpolicy="no-referrer"></a></th> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/add-footprint.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/LN2rwCAPBq6Z_-trCY7dwYy3HN1BuSOX0v3nGKoHai0/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9hZGQtZm9vdHByaW50LnBuZw" alt="逐元素加法 CUDA 内核资源占用:32 个寄存器和零共享内存" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 15:矩阵乘 cuBLAS 内核资源占用(寄存器、共享内存、线程块尺寸)</td> <td align="center">图 16:逐元素加法内核资源:32 个寄存器、无共享内存</td> </tr> </tbody> </table> </div> <p>从图 15 可见,矩阵乘法的<strong>单线程寄存器占用、共享内存占用</strong>会随矩阵尺寸动态变化。cuBLAS 内置上百种不同版本的矩阵乘内核,每种内核都依托启发式策略完成启动,而该策略需要实时获取硬件算力信息,占用率查询就是启发逻辑的一环。从原理上理解,<a href="https://alvinwan.com/how-to-tile-matrix-multiplication/" rel="nofollow">GPU 矩阵乘法基于分块(tile)计算</a>:分块数量、单块大小由输入矩阵规格与硬件参数共同决定;现代优化算法细节虽更加复杂,但这套分块思路仍是很好的理解框架。</p> <p>反观图 16,加法内核固定占用 32 个寄存器、不使用共享内存,资源需求极小,硬件资源不会成为运行瓶颈,因此无需提前查询占用率。这类算子天生轻量化。</p> <blockquote class="note"> <p>该规律可作为性能排查快捷手段:浏览 CPU 时间线,只要出现 <code>cudaOccupancyMaxActiveBlocksPerMultiprocessor</code> 调用,就代表后方是<strong>资源开销大、自适应调度启动</strong>的内核,常见于通用矩阵乘 GEMM、卷积等算子;前面无占用率查询的内核,大多是逐元素运算、规约类算子,由 PyTorch 按固定逻辑直接发起调度。</p> </blockquote> <h3 class="relative group flex items-baseline"> <a id="cudadevicesynchronize-耗时为何高达约-178-毫秒?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#cudadevicesynchronize-%E8%80%97%E6%97%B6%E4%B8%BA%E4%BD%95%E9%AB%98%E8%BE%BE%E7%BA%A6-178-%E6%AF%AB%E7%A7%92%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> cudaDeviceSynchronize 耗时为何高达约 1.78 毫秒? </span> </h3> <p><code>cudaDeviceSynchronize</code> 会阻塞 CPU 线程,直至当前 GPU 上所有计算任务全部执行完毕。剖析器会在有效采样窗口末尾执行该同步操作,目的是刷新缓存的性能事件,缺少这一步就会丢失内核耗时统计数据。</p> <p>一次仅 26 微秒 GPU 有效运算,却伴随 1.78 毫秒同步耗时,说明程序空闲占比高达 98%,是典型的<strong>开销受限型</strong>性能特征。</p> <h2 class="relative group flex items-baseline"> <a id="4096×4096-性能轨迹" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#4096%C3%974096-%E6%80%A7%E8%83%BD%E8%BD%A8%E8%BF%B9" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 4096×4096 性能轨迹 </span> </h2> <p>前文通过性能统计表分析已知:增大矩阵尺寸后,算法会从开销受限转为<strong>计算受限</strong>。</p> <p>执行下述命令,深入分析性能轨迹:</p> <pre><code class="language-bash">uv run 01_matmul_add.py --size 4096 --warmup </code></pre> <h3 class="relative group flex items-baseline"> <a id="相同内核,单次运行耗时为何参差不齐?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E7%9B%B8%E5%90%8C%E5%86%85%E6%A0%B8%EF%BC%8C%E5%8D%95%E6%AC%A1%E8%BF%90%E8%A1%8C%E8%80%97%E6%97%B6%E4%B8%BA%E4%BD%95%E5%8F%82%E5%B7%AE%E4%B8%8D%E9%BD%90%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 相同内核,单次运行耗时为何参差不齐? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/kernel-time.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/sbPqw14sT3SHbBo3DgX-dvSJMn3erZ5DQcqbkP_1_nI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9rZXJuZWwtdGltZS5wbmc" alt="同一 GPU 上 4096×4096 bf16 matmul 内核耗时在多个性能采样步骤之间发生变化" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 17:同一张显卡上,多轮采样里 4096×4096 BF16 矩阵乘内核耗时不一致</td> </tr> </tbody> </table> </div> <p>从图 17 可见,<code>ProfileStep#3</code> 对应的矩阵乘 GPU 内核运行耗时显著高于其他轮次。值得留意的是,各轮次输入完全一致,cuBLAS 启发式适配逻辑不会带来差异;CPU 任务下发时序无空隙,也并非剖析工具本身造成的数据失真。</p> <p>该轨迹点明一个理想化示例里容易忽略的关键点:<strong>即便硬件环境、代码、输入数据完全相同,GPU 内核的实际运行耗时也并非固定值</strong>。</p> <p>微调脚本参数,循环运行 20 次并采集每个步骤:</p> <pre><code class="language-diff"><span class="hljs-deletion">- schedule = torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=1)</span> <span class="hljs-addition">+ schedule = torch.profiler.schedule(wait=0, warmup=0, active=20, repeat=1)</span> <span class="hljs-deletion">- for _ in range(5):</span> <span class="hljs-addition">+ for _ in range(20):</span> </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/20-iters-kernels.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/yqyrVVRptDJX015tP6KHvmTuTb_QbgqhZaaOPqJogEU/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci8yMC1pdGVycy1rZXJuZWxzLnBuZw" alt="PyTorch 性能轨迹展示 20 次 matmul 迭代中的内核运行耗时波动" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 18:20 轮迭代下,同一份矩阵乘内核呈现明显的运行耗时波动</td> </tr> </tbody> </table> </div> <p>图 18 同样验证了上述现象:内核代码完全一致,但运算耗时各不相同。造成耗时波动的常见诱因:</p> <ul> <li>GPU 空闲或加速状态下的时钟频率变化</li> <li>显卡温升带来的性能波动</li> <li>显卡功耗调度策略</li> <li>显卡驱动后台例行维护任务</li> </ul> <p>只看平均耗时的开发者会得出结论:矩阵乘法平均耗时约 1 毫秒(5 次均值为 1084 微秒);而查看时序轨迹后能发现:除个别硬件扰动时刻外,矩阵乘法大多只需约 580 微秒。两种结论对应的优化思路天差地别,后者才符合真实运行情况。</p> <p><a id="lets-see-some-torch-compile-at-work" rel="nofollow"></a></p> <h2 class="relative group flex items-baseline"> <a id="看看-torchcompile-的实际表现" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E7%9C%8B%E7%9C%8B-torchcompile-%E7%9A%84%E5%AE%9E%E9%99%85%E8%A1%A8%E7%8E%B0" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 看看 torch.compile 的实际表现 </span> </h2> <p>使用 <code>torch.compile</code> 一直让我们感到惊喜。开发者编写普通 eager PyTorch 代码,PyTorch 会尝试捕获张量密集区域,将其转为计算图、优化,并运行生成代码。默认后端通常是 <code>TorchInductor</code>,整体编译链路如下:</p> <ol> <li><code>TorchDynamo</code>:抓取 Python 执行过程,转化为 FX 计算图</li> <li><code>AOTAutograd</code>:涉及梯度计算时,构建前向、反向传播计算图</li> <li><code>Inductor</code>:将上层计算图下沉编译为优化后的 CPU/GPU 代码</li> </ol> <p>本节结合性能剖析轨迹,讲解编译优化细节:</p> <pre><code class="language-bash">uv run 01_matmul_add.py --size 4096 --warmup --compile </code></pre> <p>开启编译参数 <code>args.compile</code> 后,执行逻辑变更如下:</p> <pre><code class="language-py"><span class="hljs-keyword">def</span> <span class="hljs-title function_">fn</span>(<span class="hljs-params">x, w, b</span>): <span class="hljs-keyword">return</span> torch.add(torch.matmul(x, w), b) fn = torch.<span class="hljs-built_in">compile</span>(fn) <span class="hljs-keyword">if</span> args.<span class="hljs-built_in">compile</span> <span class="hljs-keyword">else</span> fn </code></pre> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/compilation-region.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/yHOt_Kr3W8MorqMufzyjKHWt7CF_Pj2aCUdLOqCSRME/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9jb21waWxhdGlvbi1yZWdpb24ucG5n" alt="PyTorch 性能轨迹中高亮的 torch.compile 区域,展示 TorchDynamo 和 Inductor 调用帧" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 19:性能轨迹中标注出 Torch 编译区域,包含 TorchDynamo 与 Inductor 调用帧</td> </tr> </tbody> </table> </div> <p>图 19 中可以看到名为 <code>Torch-Compiled Region: 0/0</code> 的条目,代表当前正在使用编译后的函数。</p> <h3 class="relative group flex items-baseline"> <a id="矩阵乘与加法算子是否融合为单个-gpu-内核?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E7%9F%A9%E9%98%B5%E4%B9%98%E4%B8%8E%E5%8A%A0%E6%B3%95%E7%AE%97%E5%AD%90%E6%98%AF%E5%90%A6%E8%9E%8D%E5%90%88%E4%B8%BA%E5%8D%95%E4%B8%AA-gpu-%E5%86%85%E6%A0%B8%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 矩阵乘与加法算子是否融合为单个 GPU 内核? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/fused-ops.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/OPZuVs_UU84b7er0R7UPv-3YPqppDcSn2WIXZcKcITM/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9mdXNlZC1vcHMucG5n" alt="编译后性能轨迹显示 aten::addmm 替代 eager 模式下的 aten::add 和 aten::mm 组合" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 20:编译运行后,原先分开的<code>aten::mm</code>、<code>aten::add</code> 被替换为单个 <code>aten::addmm</code> 算子</td> </tr> </tbody> </table> </div> <p>从图 20 可以提出一个问题:乘法与加法是否真正融合为单次算子运算?</p> <p>这属于<strong>计算图层面的算子融合</strong>:Inductor 将 <code>torch.add(torch.matmul(x, w), b)</code> 改写为单次 <code>aten::addmm(b, x, w)</code> 调用。关键细节是:<strong>该优化并未生成全新的融合 CUDA 内核</strong>。GPU 底层仍沿用动态执行模式使用的同一个 cuBLAS 内核 <code>ampere_bf16_s16816gemm_bf16_128x256_ldg8_f2f_stages_64x3_nn</code>。换言之,本次融合仅发生在算子调度层,而非 GPU 内核层。</p> <blockquote class="note"> <p>PyTorch 原生接口 <a href="https://docs.pytorch.org/docs/2.12/generated/torch.addmm.html" rel="nofollow"><code>torch.addmm</code></a> 本身就整合了矩阵相乘和偏置相加两步运算。可以采集这个函数的性能轨迹,并在评论区分享观察结果。</p> </blockquote> <h3 class="relative group flex items-baseline"> <a id="torchcompile-的运行时架构" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#torchcompile-%E7%9A%84%E8%BF%90%E8%A1%8C%E6%97%B6%E6%9E%B6%E6%9E%84" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> torch.compile 的运行时架构 </span> </h3> <p>理论上理解函数编译会发生什么还不够,同样重要的是在轨迹里看到它实际如何运行。下面看一下反映 <code>torch.compile</code> 运行时架构的 CPU 侧层级:</p> <p><strong>TorchDynamo Cache Lookup</strong>:Dynamo 在这里校验当前调用是否仍匹配已编译版本,包括输入形状、数据类型、设备和张量元数据。如果存在不匹配,Dynamo 会重新编译;这项查询开销每次调用都会产生,即使编译完成后也无法省略。</p> <p><strong>Torch-Compiled Region</strong>:进入编译后版本的包装入口。</p> <p><strong>AOTDispatcher Runtime Wrapper Prologue</strong>:AOTAutograd 的运行时包装器。即便本示例不需要梯度,AOTDispatcher 也始终位于调用栈中,负责张量元数据管理和视图追踪;如果 <code>requires_grad</code> 为真,它还会设置反向传播过程。</p> <p>**## Call CompiledFxGraph **:实际生成的代码在这里运行。「CompiledFxGraph」后面的字符串是 FX 计算图的内容哈希。三轮有效采样中的哈希一致,说明命中了编译缓存。</p> <blockquote class="tip"> <p>可通过哈希值在 <code>/tmp/torchinductor_&lt;user&gt;/fxgraph</code> 路径下找到 Inductor 实际生成的 Triton/C++ 源码,便于进一步调试内核。</p> </blockquote> <h3 class="relative group flex items-baseline"> <a id="cuda-内核启动次数是否减半?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#cuda-%E5%86%85%E6%A0%B8%E5%90%AF%E5%8A%A8%E6%AC%A1%E6%95%B0%E6%98%AF%E5%90%A6%E5%87%8F%E5%8D%8A%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> CUDA 内核启动次数是否减半? </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center"><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/torch-profiler/memcpy.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/DMnmc961PoeLQUADR5Td1gfoMIgw2y1uerO5dmEq0Xc/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy90b3JjaC1wcm9maWxlci9tZW1jcHkucG5n" alt="编译后 matmul 性能轨迹显示每个步骤都会启动 Memcpy DtoD 和 GEMM 内核" referrerpolicy="no-referrer"></a></th> </tr> </thead><tbody><tr> <td align="center">图 21:编译后每轮仍启动两个 GPU 内核:设备间内存拷贝 + GEMM 矩阵乘</td> </tr> </tbody> </table> </div> <p>初看图 21 的 CPU 轨迹时,我们一度高兴地以为每轮只有一次 <code>cudaLaunchKernel</code> 调用,但这与 GPU 轨迹直接矛盾:每轮依然启动了两个内核,分别是 <strong>设备到设备内存拷贝(Memcpy DtoD)和 GEMM</strong>。回看 CPU 调用栈后可以发现,此前完全遗漏了 <code>cudaMemcpyAsync</code> 下发。</p> <p><code>addmm</code> 计算的是 <code>out = α·A·B + β·C</code>。cuBLAS 带偏置加法收尾阶段的 GEMM 会写入目标缓冲区,而这个目标缓冲区需要预先包含偏置。<strong>运算收尾(epilogue)</strong>可以理解为 GEMM 主计算之后发生的所有附加操作。在深度学习中,激活函数、偏置相加、归一化等都是常见的 GEMM 收尾逻辑,因此 cuBLAS 提供了大量带特定收尾逻辑的 GEMM 内核变体。</p> <blockquote> <p>使用 <code>torch.compile</code> 的不同 <code>mode</code> 参数会触发不同内核变体。可以自行测试,并在评论区分享观察结果。</p> </blockquote> <p>因此,Inductor 生成的代码实际执行两步:</p> <ul> <li><code>out = copy(C)</code> ← 这是 DtoD 内存拷贝(32 MB,耗时约 33 µs)</li> <li><code>out = α·(A·B) + β·out</code> ← 使用 <code>α=β=1</code> 的 GEMM,将偏置加法融合到写回阶段</li> </ul> <p>数学结果等价,但优化存在隐性开销:额外一次显存拷贝 + 复杂度略高的 GEMM 收尾逻辑。</p> <p>原本期待的融合是让 <code>x·w + b</code>(这里是 <code>out = α·A·B + β·C</code>)折叠成一个没有额外内存访问的单一内核,但实际并非如此。Inductor 保留了两次访存操作,只是把偏置拷贝表示为内存拷贝,把加法表示为 GEMM 收尾阶段。</p> <p>真正的融合实现会跳过这次内存拷贝。FlashAttention 这类手写内核会这么做,Inductor 借助 Triton 代码生成也能做到;但针对 <code>4096×4096 bf16 matmul</code>,Inductor 显然判断「使用 cuBLAS,并通过收尾阶段处理偏置」是更合适的路径。</p> <h3 class="relative group flex items-baseline"> <a id="cpu-开销不降反升" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#cpu-%E5%BC%80%E9%94%80%E4%B8%8D%E9%99%8D%E5%8F%8D%E5%8D%87" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> CPU 开销不降反升 </span> </h3> <p>对比动态执行与编译运行极易忽略的细节:</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="center">轮次</th> <th align="center">eager 耗时(ms)</th> <th align="center">compile 耗时(ms)</th> </tr> </thead><tbody><tr> <td align="center">#2</td> <td align="center">0.1</td> <td align="center">0.2</td> </tr> <tr> <td align="center">#3</td> <td align="center">0.07</td> <td align="center">0.1</td> </tr> <tr> <td align="center">#4</td> <td align="center">0.07</td> <td align="center">0.1</td> </tr> </tbody> </table> </div> <p>编译版本单轮 CPU 耗时约为原生的 2 倍。原因是每次调用都完整经过 Dynamo→AOTAutograd→Inductor 整套调度链路,同时保留原有 <code>aten::addmm</code> 调度开销。编译框架面向多算子大型模型设计,海量算子可平摊单次调用的编译开销;单算子场景下,编译调度反而带来额外性能损耗。</p> <blockquote class="tip"> <p>作为课后练习,可以查阅 <code>torch.compile</code> 文档,尝试找到能够降低 CPU 调用开销的 <code>mode</code> 参数。🤗</p> </blockquote> <h2 class="relative group flex items-baseline"> <a id="轨迹阅读速查表" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E8%BD%A8%E8%BF%B9%E9%98%85%E8%AF%BB%E9%80%9F%E6%9F%A5%E8%A1%A8" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 轨迹阅读速查表 </span> </h2> <p>本小节汇总前文出现过的模式:在性能轨迹中看到相应现象时,可以快速对照判断含义。</p> <h3 class="relative group flex items-baseline"> <a id="性能统计表" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E6%80%A7%E8%83%BD%E7%BB%9F%E8%AE%A1%E8%A1%A8" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 性能统计表 </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">观测现象</th> <th align="left">通常意味着什么</th> </tr> </thead><tbody><tr> <td align="left"><code>Self CPU time total</code> ≫ <code>Self CUDA time total</code>(CPU 单位为 ms,GPU 单位为 µs)</td> <td align="left"><strong>开销受限型</strong>:CPU 任务下发耗时远大于 GPU 实际计算耗时。可以增大工作量(更大的矩阵、批处理运算),或融合调用。</td> </tr> <tr> <td align="left"><code>Self CPU time total</code> ≈ <code>Self CUDA time total</code>,两者都是 ms</td> <td align="left"><strong>计算受限型</strong>:GPU 是性能瓶颈,这通常是更理想的状态。</td> </tr> <tr> <td align="left">某个事件独占绝大部分<code>CUDA total</code> 耗时</td> <td align="left">这就是性能热点,优先从这里开始优化。</td> </tr> <tr> <td align="left">某个事件的<code># of Calls</code> 很大</td> <td align="left">即使单次调用很便宜,频繁调用也可能形成瓶颈。检查它是否可以融合或批量化。</td> </tr> <tr> <td align="left">某一行的<code>CPU total</code> ≫ <code>Self CPU</code></td> <td align="left">大部分耗时位于内部子调用。排查时应深入嵌套事件,而不是只看父事件。</td> </tr> </tbody> </table> </div> <h3 class="relative group flex items-baseline"> <a id="cpu-时序泳道(cpu-lane)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#cpu-%E6%97%B6%E5%BA%8F%E6%B3%B3%E9%81%93%EF%BC%88cpu-lane%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> CPU 时序泳道(CPU lane) </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">看到的现象</th> <th align="left">通常意味着什么</th> </tr> </thead><tbody><tr> <td align="left">首轮<code>ProfileStep</code> 耗时明显远大于后续轮次</td> <td align="left">冷启动开销:显存工作区申请、cuBLAS 启发式选型、模块懒加载。可以增加预热迭代,或启用剖析器调度中的<code>warmup</code> 参数。</td> </tr> <tr> <td align="left"><code>record_function("...")</code> 起始与内部首个 <code>aten::*</code> 之间出现大片空档</td> <td align="left">同样是冷启动开销,只是在放大视图中的表现:标记已经进入,但算子尚未下发。</td> </tr> <tr> <td align="left"><code>cudaOccupancyMaxActiveBlocksPerMultiprocessor</code> 出现在 <code>cudaLaunchKernel</code> 之前</td> <td align="left">重型自适应内核(GEMM 矩阵乘、卷积等);cuBLAS 向驱动查询单个 SM 可容纳线程块数量,以此挑选最优内核实现。</td> </tr> <tr> <td align="left"><code>cudaLaunchKernel</code> 前方无占用率查询调用</td> <td align="left">逐元素或规约类轻量内核,资源占用固定,无需预先规划。</td> </tr> <tr> <td align="left">有效采样末尾出现很长的<code>cudaDeviceSynchronize</code></td> <td align="left">剖析器正在刷新事件;耗时主要来自 GPU 完成待处理任务,并非真实 CPU 计算开销。小规模 GPU 工作伴随长时间同步,是典型开销受限症状。</td> </tr> <tr> <td align="left">源码里没有写内存拷贝,但出现<code>cudaMemcpyAsync</code></td> <td align="left">通常是隐藏的设备到设备拷贝。常见情况是<code>addmm</code> 在 GEMM 收尾阶段之前,先用偏置初始化目标缓冲区。</td> </tr> </tbody> </table> </div> <h3 class="relative group flex items-baseline"> <a id="gpu-时序泳道(gpu-lane)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#gpu-%E6%97%B6%E5%BA%8F%E6%B3%B3%E9%81%93%EF%BC%88gpu-lane%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> GPU 时序泳道(GPU lane) </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">看到的现象</th> <th align="left">通常意味着什么</th> </tr> </thead><tbody><tr> <td align="left">GPU 时间线出现<code>Activity Buffer Request</code></td> <td align="left">剖析器正在申请或填充自身事件缓冲区;首次出现通常可以解释最初的 CPU/GPU 时间线偏移。</td> </tr> <tr> <td align="left">单轮采样内两个内核中间有空隙</td> <td align="left">运行中触发缓存申请;多轮采样仅偶然出现一次则是工具行为,非业务代码问题。</td> </tr> <tr> <td align="left">同一种内核,多轮运行耗时参差不齐</td> <td align="left">GPU 主频动态升降、芯片温升、功耗调度、驱动后台任务导致波动,不能只依赖平均值做性能评估。</td> </tr> <tr> <td align="left">内核名形如<code>ampere_bf16_s16816gemm_...</code></td> <td align="left">cuBLAS 底层矩阵乘内核;相同尺寸与精度下,动态执行与编译模式通常共用同一套内核。</td> </tr> <tr> <td align="left">GEMM 内核紧邻前置<code>Memcpy DtoD</code></td> <td align="left">这是<code>addmm</code> 收尾阶段的偏置拷贝。「融合」发生在调度器层面,而不是 CUDA 内核层面。</td> </tr> </tbody> </table> </div> <h3 class="relative group flex items-baseline"> <a id="任务下发调用链" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E4%BB%BB%E5%8A%A1%E4%B8%8B%E5%8F%91%E8%B0%83%E7%94%A8%E9%93%BE" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 任务下发调用链 </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">看到的现象</th> <th align="left">通常意味着什么</th> </tr> </thead><tbody><tr> <td align="left"><code>ProfileStep#N</code> → 自定义标记 <code>&lt;record_function name&gt;</code> → <code>aten::*</code> → <code>aten::mm</code> / <code>aten::bmm</code> / <code>aten::add</code></td> <td align="left">标准嵌套调用层级;自身耗时不含子调用,总耗时包含所有子任务。</td> </tr> <tr> <td align="left"><code>aten::matmul</code> 下沉为 <code>aten::mm</code></td> <td align="left">普通二维矩阵相乘。</td> </tr> <tr> <td align="left"><code>aten::matmul</code> 下沉为 <code>aten::bmm</code> 且附带额外 CUDA Runtime 调用</td> <td align="left">带批量维度的矩阵乘法。cuBLAS 需要更多启发式工作来选择合适的内核变体。</td> </tr> <tr> <td align="left"><code>aten::addmm(b, x, w)</code> 替代单独的 <code>aten::add</code> + <code>aten::mm</code> 组合</td> <td align="left"><strong>调度层算子融合</strong>,GPU 底层仍使用同一个 GEMM 内核,偏置加法被并入收尾阶段。</td> </tr> </tbody> </table> </div> <h3 class="relative group flex items-baseline"> <a id="torchcompile-编译相关" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#torchcompile-%E7%BC%96%E8%AF%91%E7%9B%B8%E5%85%B3" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> torch.compile 编译相关 </span> </h3> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">看到的现象</th> <th align="left">通常意味着什么</th> </tr> </thead><tbody><tr> <td align="left">CPU 时间线出现<code>Torch-Compiled Region: K/M</code> 行</td> <td align="left">当前位于编译后函数内部。</td> </tr> <tr> <td align="left">每轮都有<code>TorchDynamo Cache Lookup</code></td> <td align="left">Dynamo 校验张量形状、数据类型、设备是否匹配已缓存编译产物;编译完成后每次调用仍会产生该校验开销。</td> </tr> <tr> <td align="left">无梯度计算时仍存在<code>AOTDispatcher Runtime Wrapper Prologue</code></td> <td align="left">AOTAutograd 的运行时包装器始终位于调用栈中,负责张量元数据和视图追踪。</td> </tr> <tr> <td align="left">多轮<code>## Call CompiledFxGraph &lt;hash&gt;</code> 哈希值一致</td> <td align="left">命中生成代码缓存;生成源码位于<code>/tmp/torchinductor_&lt;user&gt;/fxgraph/&lt;hash&gt;</code>。</td> </tr> <tr> <td align="left">单算子场景编译后 CPU 耗时高于原生 Eager</td> <td align="left">正常现象:Dynamo→AOTAutograd→Inductor 整套链路带来固定开销,仅在大量算子堆叠的大模型中才能平摊成本。</td> </tr> </tbody> </table> </div> <h2 class="relative group flex items-baseline"> <a id="结论" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/torch-profiler#%E7%BB%93%E8%AE%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 结论 </span> </h2> <p>本文从极简的 <code>matmul + add</code> 入手,借它学习如何阅读 PyTorch 剖析器输出。过程中得到的一些分析思路,也适用于更大的工作负载。</p> <p>本文是《PyTorch 性能剖析》系列的第一站。后续文章会逐渐离开这个双算子示例,走向更大的构建块,并最终分析真实模型。</p> <p>感谢 <a href="https://huggingface.co/NoeFlandre">Noe Flandre</a>、<a href="https://huggingface.co/suvadityamuk">Suvaditya Mukherjee</a> 和 <a href="https://huggingface.co/ViditOstwal">Vidit Ostwal</a> 审阅本文初稿。</p>

2026/5/29
阅读更多

Codex 正在推动 AI 模型的开源与训练流程

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/hf-skills-training-codex.md">在 GitHub 上更新</a></div> <p></p><a href="https://huggingface.co/blog/assets/hf-skills-training/thumbnail-codex.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/endDv3D1ZXp8PTXcx2h9Uu_bGzFU9zd6aFThHanWrlk/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9ibG9nL2Fzc2V0cy9oZi1za2lsbHMtdHJhaW5pbmcvdGh1bWJuYWlsLWNvZGV4LnBuZw" alt="banner" referrerpolicy="no-referrer"></a><p></p> <p>继我们使用 <a href="https://huggingface.co/blog/hf-skills-training">Claude Code</a> 训练开源模型的项目之后,现在我们更进一步,将 <a href="https://developers.openai.com/codex/" rel="nofollow">Codex</a> 引入这一流程。这里的重点不是“Codex 自己开源模型”,而是让 Codex 作为编码代理,参与并自动化开源模型的训练、评估与发布全流程。为此,我们为 Codex 接入了 <a href="https://github.com/huggingface/skills" rel="nofollow">Hugging Face Skills</a> 仓库,该仓库包含了许多与机器学习和 AI 相关的“技能”,比如模型训练与评估等任务。通过 HF Skills,Codex 这样的编码代理可以实现:</p> <ul> <li>对语言模型进行微调和强化学习(RL)对齐训练</li> <li>查看、解释并基于 Trackio 的实时训练指标做出操作</li> <li>评估模型检查点并根据评估结果作出决策</li> <li>生成实验报告</li> <li>将模型导出为 GGUF 格式,方便本地部署</li> <li>将模型发布到 Hugging Face Hub</li> </ul> <p>本教程将更深入地介绍它的工作原理,并手把手教你如何使用。我们开始吧!</p> <blockquote class="note"> <p>Codex 使用 <code>AGENTS.md</code> 文件来完成特定任务,而 Claude Code 使用的是 “Skills”。幸运的是,“HF Skills” 兼容这两种方式,并可与 Claude Code、Codex 或 Gemini CLI 等主要编码代理配合使用。</p> </blockquote> <p>例如,使用 <code>HF Skills</code>,你可以对 Codex 下达如下指令:</p> <pre><code>Fine-tune Qwen3-0.6B on the dataset open-r1/codeforces-cots </code></pre> <p>Codex 将自动执行以下步骤:</p> <ol> <li>验证数据集格式</li> <li>选择合适的硬件(比如 0.6B 模型使用 t4-small)</li> <li>使用并更新带有 Trackio 监控的训练脚本</li> <li>将任务提交到 Hugging Face Jobs</li> <li>返回任务 ID 和预估费用</li> <li>根据请求查看训练进度</li> <li>如遇问题,协助你进行调试</li> </ol> <p>模型会在 Hugging Face 提供的 GPU 上训练,你可以同时做其他事情。训练完成后,你的微调模型将自动发布到 Hub,可立即使用。</p> <p>这不仅仅是一个演示工具。这套扩展系统支持生产级的训练方法,有监督微调(SFT)、直接偏好优化(DPO)和带有可验证奖励的强化学习(RL)。你可以训练 0.5B 到 7B 参数规模的模型,将它们转换为 GGUF 格式便于本地运行,还可以通过多阶段流程结合不同方法。</p> <h2 class="relative group flex items-baseline"> <a id="目标:端到端的机器学习实验" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E7%9B%AE%E6%A0%87%EF%BC%9A%E7%AB%AF%E5%88%B0%E7%AB%AF%E7%9A%84%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%AE%9E%E9%AA%8C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 目标:端到端的机器学习实验 </span> </h2> <p>我们在 Claude Code 教程中探索过单条指令的方式。而现在,我们可以让 OpenAI Codex 实现完整的端到端机器学习实验。Codex 能够:</p> <ul> <li>实时监控进度</li> <li>评估模型效果</li> <li>维护最新训练报告</li> </ul> <p>工程师可以将实验任务交由 Codex 自动执行,而自己只需查看最终报告即可。同时,Codex 还能根据训练与评估结果自动做出更多决策。</p> <p>我们开始动手吧!</p> <h2 class="relative group flex items-baseline"> <a id="环境准备与安装" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87%E4%B8%8E%E5%AE%89%E8%A3%85" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 环境准备与安装 </span> </h2> <p>在开始之前,你需要:</p> <ul> <li>一个 Hugging Face 账户,并开通 <a href="https://hf.co/pro" rel="nofollow">Pro</a> 或 <a href="https://hf.co/enterprise" rel="nofollow">Team / Enterprise</a> 付费计划(Jobs 需付费)</li> <li>一个拥有写权限的 token(在 <a href="https://huggingface.co/settings/tokens">huggingface.co/settings/tokens</a> 生成)</li> <li>安装并配置好 <a href="https://developers.openai.com/codex/" rel="nofollow">Codex</a></li> </ul> <h3 class="relative group flex items-baseline"> <a id="安装-codex" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E5%AE%89%E8%A3%85-codex" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 安装 Codex </span> </h3> <p>Codex 是 OpenAI 推出的 AI 编码代理,包含在 ChatGPT Plus、Pro、Business、Edu 和 Enterprise 等计划中。它可以将 AI 能力直接融入你的开发流程。</p> <p>参见 <a href="https://developers.openai.com/codex/" rel="nofollow">Codex 官方文档</a> 获取安装与配置说明。</p> <h3 class="relative group flex items-baseline"> <a id="安装-hugging-face-skills" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E5%AE%89%E8%A3%85-hugging-face-skills" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 安装 Hugging Face Skills </span> </h3> <p>Hugging Face Skills 仓库中包含 <code>AGENTS.md</code> 文件,Codex 会自动识别并使用它。</p> <p>克隆仓库:</p> <pre><code class="language-bash">git <span class="hljs-built_in">clone</span> https://github.com/huggingface/skills.git <span class="hljs-built_in">cd</span> skills </code></pre> <p>Codex 会自动检测到 <code>AGENTS.md</code> 文件,并加载相应的技能。你可以通过以下指令确认技能已加载:</p> <pre><code class="language-bash">codex --ask-for-approval never <span class="hljs-string">"Summarize the current instructions."</span> </code></pre> <p>详细信息请参考 <a href="https://developers.openai.com/codex/" rel="nofollow">Codex AGENTS 指南</a>。</p> <h3 class="relative group flex items-baseline"> <a id="连接-hugging-face" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E8%BF%9E%E6%8E%A5-hugging-face" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 连接 Hugging Face </span> </h3> <p>使用以下命令并输入写权限 token 来进行认证:</p> <pre><code class="language-bash">hf auth login </code></pre> <p>Codex 支持 <a href="https://developers.openai.com/codex/" rel="nofollow">MCP(模型上下文协议)</a>,你可以在配置文件中添加 Hugging Face 的 MCP 服务,提升与 Hub 的集成体验。将以下内容添加到 <code>~/.codex/config.toml</code>:</p> <pre><code class="language-toml"><span class="hljs-section">[mcp_servers.huggingface]</span> <span class="hljs-attr">command</span> = <span class="hljs-string">"npx"</span> <span class="hljs-attr">args</span> = [<span class="hljs-string">"-y"</span>, <span class="hljs-string">"mcp-remote"</span>, <span class="hljs-string">"https://huggingface.co/mcp?login"</span>] </code></pre> <p>你也可以在 <a href="https://huggingface.co/settings/mcp">Settings 页面</a> 中配置 MCP 服务。</p> <p>之后启动 Codex,会跳转到 Hugging Face MCP 的认证页面。</p> <h2 class="relative group flex items-baseline"> <a id="你的第一个-ai-实验" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA-ai-%E5%AE%9E%E9%AA%8C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 你的第一个 AI 实验 </span> </h2> <p>我们来看一个完整示例。使用 <a href="https://huggingface.co/datasets/open-r1/codeforces-cots">open-r1/codeforces-cots</a> 数据集,配合 <a href="https://huggingface.co/datasets/openai/openai_humaneval">openai_humaneval</a> 基准测试,微调一个小模型来提升其代码解题能力。</p> <blockquote class="note"> <p><code>open-r1/codeforces-cots</code> 是一个包含 Codeforces 编程题及其解答的数据集,非常适合用于模型的指令微调,帮助模型解决复杂编程问题。</p> </blockquote> <h3 class="relative group flex items-baseline"> <a id="向-codex-发起完整的微调实验请求" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E5%90%91-codex-%E5%8F%91%E8%B5%B7%E5%AE%8C%E6%95%B4%E7%9A%84%E5%BE%AE%E8%B0%83%E5%AE%9E%E9%AA%8C%E8%AF%B7%E6%B1%82" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 向 Codex 发起完整的微调实验请求 </span> </h3> <p>在你的项目目录下启动 Codex,并输入如下指令:</p> <pre><code>Start a new fine-tuning experiment to improve code solving abilities on using SFT. - Maintain a report for the experiment. - Evaluate models with the openai_humaneval benchmark - Use the open-r1/codeforces-cots dataset </code></pre> <blockquote class="tip"> <p>相比 Claude Code 教程中的单条指令方式,这里我们加了更多细节和步骤。</p> <p>你也可以尝试自己不断迭代这个实验,提出一些更开放性的问题,比如:“哪个模型最擅长代码解题?”或“哪个数据集最适合训练代码解题能力?”</p> </blockquote> <p>Codex 会分析你的请求,并生成对应的训练配置。例如,对于一个 0.6B 参数规模的模型和一个演示数据集,它会选择 <code>t4-small</code>,这是适合该模型大小的最低成本 GPU 选项。Codex 会在 <code>training_reports/&lt;model&gt;-&lt;dataset&gt;-&lt;method&gt;.md</code> 路径下创建一份新的实验报告,并在实验过程中持续更新每次运行的相关信息。</p> <details> <summary>训练报告示例</summary> <pre><code class="language-md"><span class="hljs-section"># 基础模型与数据集</span> [<span class="hljs-string">Base Model</span>](<span class="hljs-link">https://huggingface.co/Qwen/Qwen3-0.6B</span>) [<span class="hljs-string">Dataset</span>](<span class="hljs-link">https://huggingface.co/datasets/open-r1/codeforces-cots</span>) --- <span class="hljs-section"># `sft-a10g` - `TBD` - `进行中`</span> <span class="hljs-section">## 训练参数</span> | 参数 | 值 | |-----------|-------| | 方法 | SFT(TRL)| | 模型 | <span class="hljs-code">`Qwen/Qwen3-0.6B`</span> | | 数据集 | <span class="hljs-code">`open-r1/codeforces-cots`</span>(训练集,5% 验证划分)| | 最大长度 | 2048 | | 训练轮数 | 1(首次检查后延长到3)| | 每个设备的 batch 大小 | 1 | | 梯度累积步数 | 8 | | 有效 batch | 8 | | 学习率 | 5e-5 | | 权重衰减 | 0.01 | | 预热比例 | 0.03 | | 评估策略 | 每 500 步 | | 保存策略 | 每 500 步,<span class="hljs-code">`hub_strategy=every_save`</span>,最多保存2个 | | 精度 | bf16 | | 启用梯度检查点 | true | | 是否打包样本 | false | | Hub 模型仓库 | <span class="hljs-code">`burtenshaw/qwen3-codeforces-cots-sft`</span> | | 使用硬件 | a10g-small | | 超时时间 | 2 小时 | | Trackio 项目 | <span class="hljs-code">`qwen3-codeforces-cots`</span>,运行名称:<span class="hljs-code">`sft-a10g`</span> | <span class="hljs-section">## 运行状态</span> 进行中(等待提交) <span class="hljs-section">## 运行日志</span> 尚未提交(提交后会补充链接) <span class="hljs-section">## Trackio 日志</span> 等待中(任务开始后补充链接) <span class="hljs-section">## 模型评估</span> 等待中(将使用 lighteval 对基础模型和各检查点进行 <span class="hljs-code">`openai_humaneval`</span> 评估) --- <span class="hljs-section"># 实验评估结果</span> | 运行标题 | 基准测试 | 得分 | 评估任务链接 | 模型链接 | |-----------|-----------|-------|---------------------|------------| | <span class="hljs-code">`sft-a10g`</span> - <span class="hljs-code">`TBD`</span> - <span class="hljs-code">`进行中`</span> | HumanEval pass@1 | 待定 | 待定 | [<span class="hljs-string">burtenshaw/qwen3-codeforces-cots-sft</span>](<span class="hljs-link">https://huggingface.co/burtenshaw/qwen3-codeforces-cots-sft</span>) </code></pre> </details> <h3 class="relative group flex items-baseline"> <a id="训练报告实时更新" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E8%AE%AD%E7%BB%83%E6%8A%A5%E5%91%8A%E5%AE%9E%E6%97%B6%E6%9B%B4%E6%96%B0" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 训练报告实时更新 </span> </h3> <p>随着实验的推进,Codex 会不断将最新的信息和每次运行的结果写入报告中。你可以在 <code>training_reports/&lt;model&gt;-&lt;dataset&gt;-&lt;method&gt;.md</code> 文件中查看这些更新。</p> <p>例如,当实验进行中时,Codex 会将报告标题更新为如下格式:</p> <pre><code class="language-md"><span class="hljs-section"># `sft-a10g` - `TBD` - `进行中`</span> </code></pre> <p>它还会添加运行日志和 Trackio 实时监控的链接:</p> <pre><code class="language-md"><span class="hljs-section">## Run Logs</span> [<span class="hljs-string">Run Logs</span>](<span class="hljs-link">https://huggingface.co/jobs/burtenshaw/6938272ec67c9f186cfe1ae3</span>) <span class="hljs-section">## Trackio Logs</span> [<span class="hljs-string">Trackio Logs</span>](<span class="hljs-link">https://burtenshaw-trackio.hf.space/?project=qwen3-codeforces-sft&amp;metrics=train/loss&amp;runs=sft-qwen3-codeforces-20251209-175806&amp;sidebar=hidden&amp;navbar=hidden</span>) </code></pre> <p>评估结果也会更新到实验评估表中:</p> <pre><code class="language-md"><span class="hljs-section"># Experiment Evaluations</span> | Run Title | Benchmark | Score | Evaluation Job Link | Model Link | |-----------|-----------|-------|---------------------|------------| | <span class="hljs-code">`base-humaneval-a10g`</span> - <span class="hljs-code">`2025-12-09 13:47:47 UTC`</span> - <span class="hljs-code">`Completed`</span> | HumanEval pass@1 | 0.304 | [<span class="hljs-string">Logs</span>](<span class="hljs-link">https://huggingface.co/jobs/burtenshaw/69382863c67c9f186cfe1ae7</span>) | [<span class="hljs-string">Qwen/Qwen3-0.6B</span>](<span class="hljs-link">https://huggingface.co/Qwen/Qwen3-0.6B</span>) | | <span class="hljs-code">`qwen3-0.6b-lora-v1`</span> - <span class="hljs-code">`2025-12-09 13:47:47 UTC`</span> - <span class="hljs-code">`In Progress`</span> | HumanEval pass@1 | TBD | TBD | [<span class="hljs-string">burtenshaw/qwen3-codeforces-cots-sft</span>](<span class="hljs-link">https://huggingface.co/burtenshaw/qwen3-codeforces-cots-sft</span>) </code></pre> <h3 class="relative group flex items-baseline"> <a id="数据集验证" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E6%95%B0%E6%8D%AE%E9%9B%86%E9%AA%8C%E8%AF%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 数据集验证 </span> </h3> <p>数据集格式错误是训练失败最常见的原因之一,也常是训练脚本中工作量最大的部分之一。Codex 会在任务开始前验证数据集格式,并根据需要配置 TRL 训练参数或预处理数据。</p> <p>通常,Codex 会在训练前验证数据集,你也可以手动让它提前检查:</p> <pre><code>Check if open-r1/codeforces-cots works for SFT training. </code></pre> <p>Codex 会在 CPU 上快速检查(成本非常低),并返回如下结果:</p> <pre><code>Dataset validation for my-org/conversation-data: SFT: ✓ READY Found 'messages' column with conversation format DPO: ✗ INCOMPATIBLE Missing 'chosen' and 'rejected' columns </code></pre> <p>如果你的数据集需要转换格式,Codex 可以在训练开始前对数据集进行预处理:</p> <pre><code>Preprocess the dataset open-r1/codeforces-cots to use 'good_response' and 'bad_response' instead of 'chosen' and 'rejected'. </code></pre> <p>Codex 会自动预处理数据并更新训练脚本中的配置。</p> <h3 class="relative group flex items-baseline"> <a id="提交前确认" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E6%8F%90%E4%BA%A4%E5%89%8D%E7%A1%AE%E8%AE%A4" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 提交前确认 </span> </h3> <p>在 Codex 提交训练任务前,它会向你确认配置信息:</p> <pre><code>I'll fine-tune Qwen/Qwen3-0.6B on open-r1/codeforces-cots using SFT. Configuration: - Hardware: t4-small (~$0.75/hour) - Estimated time: ~20 minutes - Estimated cost: ~$0.30 - Output: username/qwen-codeforces-cots-sft The model will be pushed to Hub automatically. Should I submit? </code></pre> <p>此时你可以修改任何内容,比如更改输出仓库名称、选择其他硬件、调整训练参数等。一旦确认无误,Codex 就会提交任务。</p> <p>你也可以先进行小规模测试:</p> <pre><code>Do a quick test run on 100 examples. </code></pre> <h3 class="relative group flex items-baseline"> <a id="使用训练报告追踪进度" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E4%BD%BF%E7%94%A8%E8%AE%AD%E7%BB%83%E6%8A%A5%E5%91%8A%E8%BF%BD%E8%B8%AA%E8%BF%9B%E5%BA%A6" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用训练报告追踪进度 </span> </h3> <p>提交任务后,你可以通过训练报告追踪进度,并获取运行日志和 Trackio 日志的链接。你也可以让 Codex 获取日志、汇总训练进展,并更新训练报告。随着 Codex 执行任务,它会持续将最新信息写入训练报告中。</p> <details> <summary>Codex 示例响应</summary> <pre><code>─ Worked for 10m 38s ───────────────────────────────────────────────────────────────────────────────────────────────────────── • Training and eval jobs are live. Key details: - SFT launched on open-r1/codeforces-cots (solutions_py_decontaminated, 98/2 split) with LoRA on Qwen/Qwen3-0.6B, a10g- large, bf16, max_steps=1000, batch=1, grad_accum=8, lr=2e-5, save/eval every 200 steps, hub push burtenshaw/qwen3- codeforces-cots-sft. Job: https://huggingface.co/jobs/burtenshaw/6938272ec67c9f186cfe1ae3 (Trackio project codeforces- cots-sft, run qwen3-0.6b-lora-v1). - Baseline lighteval (HumanEval) on the base model queued on a10g-large. Job: https://huggingface.co/jobs/ - Experiment report updated with current runs and links: training_reports/qwen3-codeforces-cots-sft.md. To evaluate the fine-tuned checkpoints once the SFT job pushes to the hub, reuse the same lighteval script: hf jobs uv run --flavor a10g-large --timeout 1h --secrets HF_TOKEN -e MODEL_ID=burtenshaw/qwen3-codeforces-cots-sft -e RESULTS_ORG=burtenshaw -d /tmp/lighteval_humaneval.py (or swap MODEL_ID for a specific checkpoint path). This will log to the same results directory on the hub. 1. Monitor the two running jobs; I can fetch logs or metrics on request. 2. After a checkpoint lands, trigger the lighteval run above to compare against the baseline; then we can fill in pass@1 in the report. </code></pre> </details> <p>Trackio 会通过自动运行评估任务,帮助你监控训练和评估的得分,并选择表现最好的模型检查点(checkpoint)。如果你想了解训练任务的状态,可以让 Codex 获取日志,并以表格形式总结训练进展。</p> <p>例如,你可以直接询问:</p> <pre><code class="language-sh">Are models outperforming the base model? </code></pre> <p>Codex 会返回类似的表格总结:</p> <pre><code class="language-sh">| Model | Benchmark | Score | Evaluation Job Link | Model Link | |-----------|-----------|-------|---------------------|------------| | `qwen3-0.6b-lora-v1` - `2025-12-09 13:47:47 UTC` - `Completed` | HumanEval pass@1 | 0.342 | [Logs](&lt;<span class="hljs-built_in">link</span>&gt;) | [burtenshaw/qwen3-codeforces-cots-sft](https://huggingface.co/burtenshaw/qwen3-codeforces-cots-sft) | `base-humaneval-a10g` - `2025-12-09 13:47:47 UTC` - `Completed` | HumanEval pass@1 | 0.306 | [Logs](&lt;<span class="hljs-built_in">link</span>&gt;) | [Qwen/Qwen3-0.6B](https://huggingface.co/Qwen/Qwen3-0.6B) </code></pre> <p>通过这种方式,你可以清楚地看到微调后的模型是否优于基础模型。</p> <p>你也可以实时查看训练损失变化:</p> <p><a href="https://huggingface.co/datasets/hf-skills/images/resolve/main/codex-sft-codeforces.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/pa6RC6ydhc0__AkOPQV4HsZaf6-p5BDLvaq9JiggFDQ/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9oZi1za2lsbHMvaW1hZ2VzL3Jlc29sdmUvbWFpbi9jb2RleC1zZnQtY29kZWZvcmNlcy5wbmc" alt="Trackio 示例图表" referrerpolicy="no-referrer"></a></p> <p>Codex 会自动获取日志并更新进度。</p> <p>点击此处查看 <a href="https://burtenshaw-trackio.hf.space/?project=qwen3-codeforces-sft&amp;metrics=train/loss&amp;runs=sft-qwen3-codeforces-20251209-175806&amp;sidebar=hidden&amp;navbar=hidden" rel="nofollow">Trackio 仪表盘示例</a></p> <h3 class="relative group flex items-baseline"> <a id="使用你的模型" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E4%BD%BF%E7%94%A8%E4%BD%A0%E7%9A%84%E6%A8%A1%E5%9E%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用你的模型 </span> </h3> <p>训练完成后,模型会被上传到 Hugging Face Hub:</p> <pre><code class="language-python"><span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> AutoModelForCausalLM, AutoTokenizer model = AutoModelForCausalLM.from_pretrained(<span class="hljs-string">"burtenshaw/qwen3-codeforces-cots-sft"</span>) tokenizer = AutoTokenizer.from_pretrained(<span class="hljs-string">"burtenshaw/qwen3-codeforces-cots-sft"</span>) </code></pre> <p>Transformers 是一个非常优秀的标准工具,我们也可以轻松地将训练好的模型转换为 GGUF 格式,用于本地部署。这是因为训练技能中已经包含了将模型转换为 GGUF 的说明和支持脚本。</p> <pre><code>Convert my fine-tuned model to GGUF with Q4_K_M quantization. Push to username/my-model-gguf. </code></pre> <p>Codex 会自动将模型转换为 GGUF 格式,应用指定的量化策略,并将其推送到 Hugging Face Hub。如果你使用了 LoRA 适配器进行训练,它还会将这些适配器合并回基础模型中。</p> <p>在本地运行模型:</p> <pre><code class="language-bash">llama-server -hf &lt;username&gt;/&lt;model-name&gt;:&lt;quantization&gt; <span class="hljs-comment"># For example, to run the Qwen3-1.7B-GGUF model on your local machine:</span> llama-server -hf unsloth/Qwen3-1.7B-GGUF:Q4_K_M </code></pre> <h3 class="relative group flex items-baseline"> <a id="硬件与成本" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E7%A1%AC%E4%BB%B6%E4%B8%8E%E6%88%90%E6%9C%AC" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 硬件与成本 </span> </h3> <p>Codex 会根据你的模型规模自动选择合适的硬件,但了解背后的取舍逻辑,有助于你做出更明智的决策。你可以参考这个 <a href="https://github.com/huggingface/skills/blob/main/hf-llm-trainer/skills/model-trainer/references/hardware_guide.md" rel="nofollow">硬件指南</a> 来了解各种硬件的选择和成本,不过 Codex 会自动帮你选择最优配置。</p> <ul> <li><p>对于 <strong>小于 10 亿参数的微型模型</strong>,<code>t4-small</code> 是一个很好的选择。这类模型训练速度快,成本大约在 <strong>$1-2</strong>,非常适合教学或实验用途。</p> </li> <li><p>对于 <strong>小模型(1-3B 参数)</strong>,推荐使用 <code>t4-medium</code> 或 <code>a10g-small</code>。训练耗时几个小时,成本在 <strong>$5-15</strong> 左右。</p> </li> <li><p>对于 <strong>中等模型(3-7B 参数)</strong>,需要使用 <code>a10g-large</code> 或 <code>a100-large</code>,同时配合 LoRA 微调。完整微调不太可行,但借助 LoRA 技术仍然可以高效训练。生产级别训练预算约为 <strong>$15-40</strong>。</p> </li> <li><p>对于 <strong>大型模型(超过 7B)</strong>,目前 HF Skills Jobs 暂不支持。但请保持关注,我们正在开发支持大模型的能力!</p> </li> </ul> <h2 class="relative group flex items-baseline"> <a id="接下来可以做什么?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E6%8E%A5%E4%B8%8B%E6%9D%A5%E5%8F%AF%E4%BB%A5%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 接下来可以做什么? </span> </h2> <p>我们已经展示了 Codex 如何处理模型微调的完整生命周期,验证数据、选择硬件、生成训练脚本、提交任务、监控进度,以及转换输出。</p> <p>你可以尝试以下操作:</p> <ul> <li>使用你自己的数据集微调一个模型</li> <li>进行更大规模的实验,使用多个模型和数据集,并让代理自动生成训练报告</li> <li>使用 GRPO 方法在数学或代码任务上训练一个推理能力模型,并生成完整的实验报告</li> </ul> <p>这个 <a href="https://hf-learn.short.gy/gh-hf-skills" rel="nofollow">Codex 扩展是开源的</a>,你可以根据自己的流程进行扩展和定制,或者将其作为其他训练场景的起点。</p> <hr> <h2 class="relative group flex items-baseline"> <a id="资源链接" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#%E8%B5%84%E6%BA%90%E9%93%BE%E6%8E%A5" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 资源链接 </span> </h2> <h3 class="relative group flex items-baseline"> <a id="codex" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#codex" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Codex </span> </h3> <ul> <li><a href="https://developers.openai.com/codex/" rel="nofollow">Codex 官方文档</a> ,OpenAI 的 AI 编码代理</li> <li><a href="https://developers.openai.com/codex/" rel="nofollow">Codex 快速上手</a></li> <li><a href="https://developers.openai.com/codex/" rel="nofollow">Codex AGENTS 指南</a> ,使用 AGENTS.md 文件说明</li> </ul> <h3 class="relative group flex items-baseline"> <a id="hugging-face-skills" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/hf-skills-training-codex#hugging-face-skills" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Hugging Face Skills </span> </h3> <ul> <li><a href="https://github.com/huggingface/skills/blob/main/hf-llm-trainer/skills/model-trainer/SKILL.md" rel="nofollow">SKILL.md</a> ,技能文档</li> <li><a href="https://github.com/huggingface/skills/blob/main/hf-llm-trainer/skills/model-trainer/references/training_methods.md" rel="nofollow">训练方法指南</a> ,介绍 SFT、DPO、GRPO 等方法</li> <li><a href="https://github.com/huggingface/skills/blob/main/hf-llm-trainer/skills/model-trainer/references/hardware_guide.md" rel="nofollow">硬件指南</a></li> <li><a href="https://huggingface.co/docs/trl">TRL 文档</a> ,Hugging Face 的训练库</li> <li><a href="https://huggingface.co/docs/huggingface_hub/guides/jobs">HF Jobs 文档</a> ,云端训练任务指南</li> <li><a href="https://huggingface.co/docs/trackio">Trackio 文档</a> ,实时训练监控工具</li> </ul>

2025/12/11
阅读更多

构建开放的未来——我们与 Google Cloud 的全新合作伙伴关系

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/google-cloud.md">在 GitHub 上更新</a></div> <img src="https://imgproxy.citrusreader.com/fK9-ooBYGaiEk7p8UtZAMGp7vh1gbxTYL4JMJOAIG3Y/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9nb29nbGUtY2xvdWQvZ29vZ2xlJTIwY2xvdWQlMjBibG9ncG9zdCUyMHRpdGxlLnBuZw" referrerpolicy="no-referrer"> <p></p>今天,我们很高兴宣布与 Google Cloud 建立更深入的合作伙伴关系,让更多企业能够使用开源模型构建自己的人工智能。<p></p> <p>Hugging Face 的 Jeff Boudier 表示: <em>“Google 一直是开放式 AI 领域的重要推动者——从最初的 Transformer 到如今的 Gemma 模型。 我相信未来每一家企业都将能构建并定制属于自己的 AI。通过这次战略合作,我们让这一切在 Google Cloud 上变得更加简单。”</em></p> <p>Google Cloud 产品管理高级总监 Ryan J. Salva 表示: <em>“Hugging Face 是推动全球大中小企业访问、使用并定制超过 200 万个开源模型的核心力量,我们也自豪地为社区贡献了超过 1000 个模型。”</em> <em>“携手合作,我们将让 Google Cloud 成为使用开源模型构建 AI 的最佳平台。”</em></p> <h2 class="relative group flex items-baseline"> <a id="面向-google-cloud-客户的合作" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/google-cloud#%E9%9D%A2%E5%90%91-google-cloud-%E5%AE%A2%E6%88%B7%E7%9A%84%E5%90%88%E4%BD%9C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 面向 Google Cloud 客户的合作 </span> </h2> <p>Google Cloud 客户已经在其领先的 AI 服务中使用来自 Hugging Face 的开源模型。在 Vertex AI 中,最受欢迎的开源模型只需几次点击即可在 Model Garden 中部署。 对于希望更灵活掌控 AI 基础设施的客户,也可在 GKE AI/ML 中找到类似的模型库,或使用由 Hugging Face 维护的预配置环境。客户还可以通过 Cloud Run GPU 运行推理任务,实现无服务器的开源模型部署。</p> <p>我们与 Google Cloud 的共同目标是:充分利用各项服务的独特能力,为客户提供无缝、灵活的使用体验。</p> <img src="https://imgproxy.citrusreader.com/wat46laPKcyyhzw8L5AmW5uyxABWQ04lblGGmjF5trM/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9nb29nbGUtY2xvdWQvZ29vZ2xlLWNsb3VkLXBhcnRuZXJzaGlwLnBuZw" referrerpolicy="no-referrer"> <h2 class="relative group flex items-baseline"> <a id="通往开源模型的高速通道为-google-cloud-用户打造的快捷体验" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/google-cloud#%E9%80%9A%E5%BE%80%E5%BC%80%E6%BA%90%E6%A8%A1%E5%9E%8B%E7%9A%84%E9%AB%98%E9%80%9F%E9%80%9A%E9%81%93%E4%B8%BA-google-cloud-%E7%94%A8%E6%88%B7%E6%89%93%E9%80%A0%E7%9A%84%E5%BF%AB%E6%8D%B7%E4%BD%93%E9%AA%8C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 通往开源模型的高速通道——为 Google Cloud 用户打造的快捷体验 </span> </h2> <p>过去三年中,Google Cloud 用户对 Hugging Face 的使用量增长了 10 倍,如今每月的模型下载量已达数十 PB,处理请求高达数十亿次。</p> <p>为了让 Google Cloud 客户在使用 Hugging Face 的模型和数据集时获得最佳体验,我们正携手打造一个全新的 CDN Gateway。该网关基于 Hugging Face 的 Xet 优化存储与数据传输技术,以及 Google Cloud 的先进存储与网络能力构建。</p> <p>通过这个 CDN Gateway,Hugging Face 的模型和数据集将直接缓存在 Google Cloud 上,大幅减少下载时间,并提升 Google Cloud 用户在模型供应链方面的稳定性和可靠性。 无论你是在使用 Vertex、GKE、Cloud Run,还是在 Compute Engine 中自建 AI 系统,都能享受到更快的响应速度与更简化的模型管理。</p> <h2 class="relative group flex items-baseline"> <a id="面向-hugging-face-用户的合作" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/google-cloud#%E9%9D%A2%E5%90%91-hugging-face-%E7%94%A8%E6%88%B7%E7%9A%84%E5%90%88%E4%BD%9C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 面向 Hugging Face 用户的合作 </span> </h2> <p>Hugging Face 的 <a href="https://endpoints.huggingface.co/" rel="nofollow">Inference Endpoints</a> 是最快捷的模型部署方式,只需几次点击即可完成。从这次合作开始,我们将把 Google Cloud 的高性能与高性价比带给 Hugging Face 用户,首先体现在 Inference Endpoints 上——未来将推出更多实例类型,并带来价格下调!</p> <img src="https://imgproxy.citrusreader.com/qqv2rVfrrK0mXF5NKXU8RC1Zn7Qh_-2gY-UJV0IiLrI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9nb29nbGUtY2xvdWQvaW5mZXJlbmNlLWVuZHBvaW50cy1nb29nbGUtY2xvdWQucG5n" referrerpolicy="no-referrer"> <p>我们将确保这一系列产品与技术合作成果能惠及 Hugging Face 上超过 1000 万名 AI 构建者。 从模型页面直接部署到 Vertex Model Garden 或 GKE 只需几步操作;在 Hugging Face 企业账户中私有托管的模型,也能像使用公共模型一样方便、安全。</p> <p>Google 的 TPU(定制 AI 加速芯片)如今已发展到第七代,性能和软件支持持续提升。我们希望 Hugging Face 用户能够充分利用当前和未来的 TPU,在构建开源模型时享受到与 GPU 同样便捷的体验。 得益于库的原生支持,TPU 的使用将比以往更简单。</p> <p>此外,这次合作还将让 Hugging Face 借助 Google 在安全技术方面的领先优势,使平台上数百万个开源模型更安全。 依托 <a href="https://www.virustotal.com/gui/home/upload" rel="nofollow">VirusTotal</a>、<a href="https://cloud.google.com/security/products/threat-intelligence" rel="nofollow">Google Threat Intelligence</a> 和 <a href="https://www.mandiant.com/" rel="nofollow">Mandiant</a> 的技术支持,我们将共同保障 Hugging Face Hub 上的模型、数据集和 Spaces 的安全。</p> <h2 class="relative group flex items-baseline"> <a id="共同构建开放的-ai-未来" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/google-cloud#%E5%85%B1%E5%90%8C%E6%9E%84%E5%BB%BA%E5%BC%80%E6%94%BE%E7%9A%84-ai-%E6%9C%AA%E6%9D%A5" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 共同构建开放的 AI 未来 </span> </h2> <p>我们期待一个未来:每家企业都能用开源模型构建属于自己的 AI,并在安全可控的基础设施上进行部署。 我们非常期待通过与 Google Cloud 的深入合作,让这一愿景加速实现——无论你使用的是 Vertex AI Model Garden、Google Kubernetes Engine、Cloud Run,还是 Hugging Face Inference Endpoints。</p> <p>有什么想让我们在这次合作中改进或新增的内容?欢迎在评论区告诉我们!</p> <img src="https://imgproxy.citrusreader.com/CThr_Zy-JK1wYTdtWXqDq8MipEU50jkHGBBg0SE9cAI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9nb29nbGUtY2xvdWQvbWNmYWNlLWJpbGxpb24tbW9kZWwtc2VydmVkLWNvbXByZXNzZWQucG5n" referrerpolicy="no-referrer">

2025/11/13
阅读更多

使用 NVIDIA Isaac 构建医疗机器人:从仿真到部署

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/lerobotxnvidia-healthcare.md">在 GitHub 上更新</a></div> <h2 class="relative group flex items-baseline"> <a id="摘要" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%91%98%E8%A6%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 摘要 </span> </h2> <p>一篇实用指南,手把手教你如何采集数据、训练策略,并将自动化医疗机器人工作流程部署到真实硬件上。</p> <h2 class="relative group flex items-baseline"> <a id="目录" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%9B%AE%E5%BD%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 目录 </span> </h2> <ul> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E4%BD%BF%E7%94%A8-nvidia-isaac-%E6%9E%84%E5%BB%BA%E5%8C%BB%E7%96%97%E6%9C%BA%E5%99%A8%E4%BA%BA%E4%BB%8E%E4%BB%BF%E7%9C%9F%E5%88%B0%E9%83%A8%E7%BD%B2" rel="nofollow">使用 NVIDIA Isaac 构建医疗机器人:从仿真到部署</a></p> <ul> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%91%98%E8%A6%81" rel="nofollow">摘要</a></p> </li> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%9B%AE%E5%BD%95" rel="nofollow">目录</a></p> </li> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%AE%80%E4%BB%8B" rel="nofollow">简介</a></p> </li> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#so-arm-%E5%85%A5%E9%97%A8%E5%B7%A5%E4%BD%9C%E6%B5%81%E6%9E%84%E5%BB%BA%E4%B8%80%E5%8F%B0%E6%89%8B%E6%9C%AF%E8%BE%85%E5%8A%A9%E6%9C%BA%E5%99%A8%E4%BA%BA" rel="nofollow">SO-ARM 入门工作流:构建一台手术辅助机器人</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%8A%80%E6%9C%AF%E5%AE%9E%E7%8E%B0" rel="nofollow">技术实现</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E4%BB%BF%E7%9C%9F%E4%B8%8E%E7%8E%B0%E5%AE%9E%E7%BB%93%E5%90%88%E7%9A%84%E8%AE%AD%E7%BB%83%E6%96%B9%E6%B3%95" rel="nofollow">仿真与现实结合的训练方法</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%A1%AC%E4%BB%B6%E8%A6%81%E6%B1%82" rel="nofollow">硬件要求</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86%E5%AE%9E%E7%8E%B0" rel="nofollow">数据采集实现</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E4%BB%BF%E7%9C%9F%E9%81%A5%E6%93%8D%E4%BD%9C%E6%8E%A7%E5%88%B6" rel="nofollow">仿真遥操作控制</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%A8%A1%E5%9E%8B%E8%AE%AD%E7%BB%83%E6%B5%81%E7%A8%8B" rel="nofollow">模型训练流程</a></li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%AE%8C%E6%95%B4%E7%9A%84%E4%BB%BF%E7%9C%9F%E9%87%87%E9%9B%86-%E8%AE%AD%E7%BB%83-%E8%AF%84%E4%BC%B0%E6%B5%81%E7%A8%8B" rel="nofollow">完整的仿真采集-训练-评估流程</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%9C%A8%E4%BB%BF%E7%9C%9F%E4%B8%AD%E7%94%9F%E6%88%90%E5%90%88%E6%88%90%E6%95%B0%E6%8D%AE" rel="nofollow">在仿真中生成合成数据</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E8%AE%AD%E7%BB%83%E5%92%8C%E8%AF%84%E4%BC%B0%E7%AD%96%E7%95%A5" rel="nofollow">训练和评估策略</a></li> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%B0%86%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2%E4%B8%BA-tensorrt" rel="nofollow">将模型转换为 TensorRT</a></li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B" rel="nofollow">快速开始</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E8%B5%84%E6%BA%90%E9%93%BE%E6%8E%A5" rel="nofollow">资源链接</a></li> </ul> </li> </ul> </li> </ul> <h2 class="relative group flex items-baseline"> <a id="简介" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%AE%80%E4%BB%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 简介 </span> </h2> <p>仿真一直是医学影像中弥补数据缺口的重要手段,但在医疗机器人领域,它过去往往速度太慢、系统割裂,或难以迁移到现实应用中。</p> <p>NVIDIA Isaac for Healthcare 是一个专为 AI 医疗机器人开发者打造的框架,提供从数据采集到训练、评估再到部署的全流程工具链,适用于仿真环境与真实硬件。特别是在 v0.4 版本中,Isaac 提供了一个 <a href="https://github.com/isaac-for-healthcare/i4h-workflows/blob/main/workflows/so_arm_starter/README.md" rel="nofollow">SO-ARM 入门工作流</a> 以及 <a href="https://github.com/isaac-for-healthcare/i4h-workflows/blob/main/tutorials/assets/bring_your_own_or/README.md" rel="nofollow">自定义手术室教程</a>,帮助开发者低门槛快速构建并验证自动化手术机器人。</p> <p>本文将带你深入了解这一工作流及其技术细节,帮助你前所未有地快速搭建手术助手机器人。</p> <h2 class="relative group flex items-baseline"> <a id="so-arm-入门工作流:构建一台手术辅助机器人" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#so-arm-%E5%85%A5%E9%97%A8%E5%B7%A5%E4%BD%9C%E6%B5%81%EF%BC%9A%E6%9E%84%E5%BB%BA%E4%B8%80%E5%8F%B0%E6%89%8B%E6%9C%AF%E8%BE%85%E5%8A%A9%E6%9C%BA%E5%99%A8%E4%BA%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> SO-ARM 入门工作流:构建一台手术辅助机器人 </span> </h2> <p>SO-ARM 入门工作流提供了一种全新的方式来探索手术辅助任务,提供了一整套从采集数据到部署到真实设备的端到端流程:</p> <ul> <li>使用 LeRobot 平台与 SO-ARM 采集真实与仿真数据</li> <li>微调 GR00t N1.5 模型,在 IsaacLab 中评估,然后部署到硬件</li> </ul> <p>这套流程为开发者提供了一个安全、可重复的训练环境,可在进入真实手术室前不断优化机器人技能。</p> <h3 class="relative group flex items-baseline"> <a id="技术实现" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%8A%80%E6%9C%AF%E5%AE%9E%E7%8E%B0" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 技术实现 </span> </h3> <p>该工作流采用三阶段流程,整合了仿真与真实硬件:</p> <ol> <li><strong>数据采集</strong>:结合仿真与真实环境中的遥操作演示,使用 SO101 和 LeRobot 平台</li> <li><strong>模型训练</strong>:在混合数据集上使用双摄像头视觉输入微调 GR00T N1.5</li> <li><strong>策略部署</strong>:基于 RTI DDS 通信协议,将训练好的模型实时运行在真实硬件上</li> </ol> <p>值得一提的是,超过 93% 的策略训练数据来自仿真环境,充分说明仿真技术在缩小机器人数据鸿沟方面的优势。</p> <h3 class="relative group flex items-baseline"> <a id="仿真与现实结合的训练方法" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E4%BB%BF%E7%9C%9F%E4%B8%8E%E7%8E%B0%E5%AE%9E%E7%BB%93%E5%90%88%E7%9A%84%E8%AE%AD%E7%BB%83%E6%96%B9%E6%B3%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 仿真与现实结合的训练方法 </span> </h3> <p>现实世界的机器人训练成本高、操作难度大;而纯粹的仿真又很难完全还原现实复杂性。该流程通过约 70 个仿真演示和 10–20 个真实演示相结合,在模拟多样场景的同时,也保留真实数据的可靠性。最终训练出的策略能更好地泛化,不局限于单一环境。</p> <h3 class="relative group flex items-baseline"> <a id="硬件要求" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E7%A1%AC%E4%BB%B6%E8%A6%81%E6%B1%82" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 硬件要求 </span> </h3> <p>工作流所需的硬件包括:</p> <ul> <li><strong>GPU</strong>:支持 RT Core 的架构(Ampere 或更新)且显存 ≥30GB,用于运行 GR00T N1.5 推理</li> <li><strong>SO-ARM101 Follower</strong>:6 自由度高精度机械臂,配备手腕摄像头与房间摄像头,采用 WOWROBO 视觉组件,并通过 3D 打印转接头固定</li> <li><strong>SO-ARM101 Leader</strong>:6 自由度的遥操作控制器,用于采集专家演示</li> </ul> <p>所有仿真、训练和部署任务(部署需使用 3 台计算机)均可在一台 <a href="https://www.nvidia.com/en-us/products/workstations/dgx-spark/" rel="nofollow">DGX Spark</a> 上完成。</p> <h3 class="relative group flex items-baseline"> <a id="数据采集实现" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86%E5%AE%9E%E7%8E%B0" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 数据采集实现 </span> </h3> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot-blog/nvidia-healthcare/lerobotxnvidia-healthcare-real-demo.gif" rel="nofollow"><img src="https://imgproxy.citrusreader.com/R3nJMFkN4nJtlaAPw8wUsMp6uM9xYJFTV9Y73tHtqhY/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vbGVyb2JvdC1ibG9nL252aWRpYS1oZWFsdGhjYXJlL2xlcm9ib3R4bnZpZGlhLWhlYWx0aGNhcmUtcmVhbC1kZW1vLmdpZg" alt="so100-healthcare-real-demo" referrerpolicy="no-referrer"></a></p> <p><strong>在真实环境中采集数据(适用于 SO-ARM101 硬件或任何 LeRobot 支持的版本):</strong></p> <pre><code class="language-bash">python lerobot-record \ --robot.type=so101_follower \ --robot.port=&lt;follower_port_id&gt; \ --robot.cameras=<span class="hljs-string">"{wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, room: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}"</span> \ --robot.id=so101_follower_arm \ --teleop.type=so101_leader \ --teleop.port=&lt;leader_port_id&gt; \ --teleop.id=so101_leader_arm \ --dataset.repo_id=&lt;user&gt;/surgical_assistance/surgical_assistance \ --dataset.num_episodes=15 \ --dataset.single_task=<span class="hljs-string">"为外科医生准备并递送手术器械"</span> </code></pre> <hr> <p><strong>在仿真环境中采集数据:</strong></p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot-blog/nvidia-healthcare/lerobotxnvidia-healthcare-sim-demo.gif" rel="nofollow"><img src="https://imgproxy.citrusreader.com/Xh7mEJDcDWQBVyjg08RzQGbNyMwEEQyR2LfgUA9q8co/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vbGVyb2JvdC1ibG9nL252aWRpYS1oZWFsdGhjYXJlL2xlcm9ib3R4bnZpZGlhLWhlYWx0aGNhcmUtc2ltLWRlbW8uZ2lm" alt="so100-healthcare-sim-demo" referrerpolicy="no-referrer"></a></p> <pre><code class="language-bash"><span class="hljs-comment"># 使用键盘遥操作</span> python -m simulation.environments.teleoperation_record \ --enable_cameras \ --record \ --dataset_path=/path/to/save/dataset.hdf5 \ --teleop_device=keyboard <span class="hljs-comment"># 使用 SO-ARM101 Leader 机械臂进行遥操作</span> python -m simulation.environments.teleoperation_record \ --port=&lt;your_leader_arm_port_id&gt; \ --enable_cameras \ --record \ --dataset_path=/path/to/save/dataset.hdf5 </code></pre> <h3 class="relative group flex items-baseline"> <a id="仿真遥操作控制" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E4%BB%BF%E7%9C%9F%E9%81%A5%E6%93%8D%E4%BD%9C%E6%8E%A7%E5%88%B6" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 仿真遥操作控制 </span> </h3> <p>没有 SO-ARM101 硬件的用户可以使用键盘控制仿真机械臂:</p> <ul> <li>关节 1(肩部旋转):Q(+)/ U(-)</li> <li>关节 2(肩部抬起):W(+)/ I(-)</li> <li>关节 3(肘部弯曲):E(+)/ O(-)</li> <li>关节 4(手腕弯曲):A(+)/ J(-)</li> <li>关节 5(手腕旋转):S(+)/ K(-)</li> <li>关节 6(夹爪开合):D(+)/ L(-)</li> <li>R 键:重置录制环境</li> <li>N 键:标记当前演示成功</li> </ul> <h3 class="relative group flex items-baseline"> <a id="模型训练流程" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E6%A8%A1%E5%9E%8B%E8%AE%AD%E7%BB%83%E6%B5%81%E7%A8%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 模型训练流程 </span> </h3> <p>完成仿真与真实数据采集后,将其转换并组合训练:</p> <pre><code class="language-bash"><span class="hljs-comment"># 将仿真数据转为 LeRobot 格式</span> python -m training.hdf5_to_lerobot \ --repo_id=surgical_assistance_dataset \ --hdf5_path=/path/to/your/sim_dataset.hdf5 \ --task_description=<span class="hljs-string">"自动执行手术器械准备与递送任务"</span> <span class="hljs-comment"># 在混合数据集上微调 GR00T N1.5</span> python -m training.gr00t_n1_5.train \ --dataset_path /path/to/your/surgical_assistance_dataset \ --output_dir /path/to/surgical_checkpoints \ --data_config so100_dualcam </code></pre> <p>训练后的模型可处理自然语言指令,如“为医生准备手术刀”或“把镊子递给我”,并控制机器人执行相应动作。借助 LeRobot 的最新版本(0.4.0),你可以直接在 LeRobot 中原生训练 Gr00t N1.5!</p> <h2 class="relative group flex items-baseline"> <a id="完整的仿真采集-训练-评估流程" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%AE%8C%E6%95%B4%E7%9A%84%E4%BB%BF%E7%9C%9F%E9%87%87%E9%9B%86-%E8%AE%AD%E7%BB%83-%E8%AF%84%E4%BC%B0%E6%B5%81%E7%A8%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 完整的仿真采集-训练-评估流程 </span> </h2> <p>仿真在形成“采集→训练→评估→部署”的循环中最具价值。</p> <p>从 v0.3 开始,IsaacLab 完整支持这一流程:</p> <h3 class="relative group flex items-baseline"> <a id="在仿真中生成合成数据" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%9C%A8%E4%BB%BF%E7%9C%9F%E4%B8%AD%E7%94%9F%E6%88%90%E5%90%88%E6%88%90%E6%95%B0%E6%8D%AE" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 在仿真中生成合成数据 </span> </h3> <ul> <li>使用键盘或硬件控制器遥操作机器人</li> <li>记录多摄像头视角、机器人状态与动作</li> <li>构建包含极端情况的多样化数据集,这些情况在现实中难以安全采集</li> </ul> <h3 class="relative group flex items-baseline"> <a id="训练和评估策略" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E8%AE%AD%E7%BB%83%E5%92%8C%E8%AF%84%E4%BC%B0%E7%AD%96%E7%95%A5" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 训练和评估策略 </span> </h3> <ul> <li>深度集成 Isaac Lab 的强化学习框架(如 PPO)</li> <li>可同时运行数千个仿真环境</li> <li>内置轨迹分析与成功率指标</li> <li>支持在多种情境下进行统计验证</li> </ul> <h3 class="relative group flex items-baseline"> <a id="将模型转换为-tensorrt" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%B0%86%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2%E4%B8%BA-tensorrt" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 将模型转换为 TensorRT </span> </h3> <ul> <li>自动化优化以适应生产部署需求</li> <li>支持动态输入形状和多摄像头推理</li> <li>提供性能基准测试工具,确保实时运行能力</li> </ul> <p>这极大地缩短了从实验到部署的周期,让 sim2real 成为日常开发的一部分。</p> <h2 class="relative group flex items-baseline"> <a id="快速开始" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 快速开始 </span> </h2> <p>SO-ARM 入门工作流已开放,立即开始:</p> <ol> <li><p>克隆代码库: <code>git clone https://github.com/isaac-for-healthcare/i4h-workflows.git</code></p> </li> <li><p>选择工作流: 推荐从 SO-ARM 入门工作流开始,也可以探索其他工作流</p> </li> <li><p>运行初始化脚本: 每个工作流都带有自动化的安装脚本(如 <code>tools/env_setup_so_arm_starter.sh</code>)</p> </li> </ol> <h3 class="relative group flex items-baseline"> <a id="资源链接" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobotxnvidia-healthcare#%E8%B5%84%E6%BA%90%E9%93%BE%E6%8E%A5" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 资源链接 </span> </h3> <ul> <li><a href="https://github.com/isaac-for-healthcare/i4h-workflows" rel="nofollow">GitHub 项目地址</a>:完整工作流实现</li> <li><a href="https://isaac-for-healthcare.github.io/i4h-docs/" rel="nofollow">官方文档</a>:安装与使用说明</li> <li><a href="https://huggingface.co/nvidia/GR00T-N1.5-3B">GR00T 模型页面</a>:预训练模型下载</li> <li><a href="https://huggingface.co/docs/lerobot/so101">硬件指南</a>:SO-ARM101 安装配置说明</li> <li><a href="https://github.com/huggingface/lerobot" rel="nofollow">LeRobot 项目</a>:端到端机器人学习平台</li> </ul>

2025/10/29
阅读更多

经同意的语音克隆

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/voice-consent-gate.md">在 GitHub 上更新</a></div> <p></p><strong>在这篇博客文章中,我们介绍了“语音同意验证机制 (voice consent gate)”的概念,支持通过明确同意来进行语音克隆。我们还提供了一个 <a href="https://huggingface.co/spaces/society-ethics/RepeatAfterMe">示例 Space 应用</a> 和 <a href="https://huggingface.co/spaces/society-ethics/RepeatAfterMe/tree/main">相关代码</a>,帮助大家快速上手这一想法。</strong><p></p> <img src="https://imgproxy.citrusreader.com/fXw8JclT2gdwIxIUTC-EueAA9aEyPV3hO1JjHvajv_o/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9zcGFjZXMvc29jaWV0eS1ldGhpY3MvUmVwZWF0QWZ0ZXJNZS9yZXNvbHZlL21haW4vYXNzZXRzL3ZvaWNlX2NvbnNlbnRfZ2F0ZS5wbmc" alt="Line-drawing/clipart of a gate, where the family name says Consent" width="50%" referrerpolicy="no-referrer"> <p>近年来,逼真的语音生成技术已经达到了令人惊讶的水平。在某些情况下,生成出来的合成语音几乎能以假乱真,和真人的声音非常相似。如今,曾经只存在于科幻小说中的“语音克隆”已经成为现实。只需要几秒钟的录音,就能让任何人的声音“说出”任何内容。</p> <p>语音生成,尤其是语音克隆技术,既有风险也有益处。它可能被用于制作“深度伪造”内容,例如 <a href="https://www.reuters.com/world/us/fcc-finalizes-6-million-fine-over-ai-generated-biden-robocalls-2024-09-26/" rel="nofollow">有人用前总统 Biden 的克隆语音进行自动电话宣传</a>,误导公众以为他说过其实并未说的话。但与此同时,语音克隆也可以带来积极作用,比如 <a href="https://www.nature.com/articles/s41598-024-84728-y" rel="nofollow">帮助失语者</a> <a href="https://www.thetimes.com/uk/healthcare/article/elevenlabs-voice-clone-ai-als-t3ntnpcl7" rel="nofollow">重新用自己的声音表达</a>,或者辅助人们学习语言和方言。</p> <p>那么,我们该如何实现“有意义的使用”而不是“恶意的滥用”?我们正在探索一种可能的答案:引入一个**语音同意验证机制 (voice consent gate)**。也就是说,只有当说话人明确表达了同意,语音克隆模型才能使用其声音。换句话说,模型不会擅自“说出”你的声音,除非你亲口同意。</p> <p>下面是我们对这一想法的基础演示:</p> <iframe src="https://society-ethics-repeatafterme.hf.space/" frameborder="0" width="850" height="450" sandbox="allow-scripts" referrerpolicy="same-origin"></iframe> <h2 class="relative group flex items-baseline"> <a id="实践中的伦理:将同意融入系统基础设施" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/voice-consent-gate#%E5%AE%9E%E8%B7%B5%E4%B8%AD%E7%9A%84%E4%BC%A6%E7%90%86%EF%BC%9A%E5%B0%86%E5%90%8C%E6%84%8F%E8%9E%8D%E5%85%A5%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 实践中的伦理:将“同意”融入系统基础设施 </span> </h2> <p>语音同意门是我们正在尝试的一种基础设施设计,用来把“<strong>同意</strong>”这样的伦理原则直接嵌入到 AI 系统的工作流程中。在我们的演示中,模型只有在检测到说话人清楚地说出了同意语句之后,才会启动。也就是说,“同意”成为系统运行的前提条件,让原本抽象的伦理原则变成了具体可操作的系统规则,并形成可追溯、可审核的交互记录:AI 模型只会在明确同意之后才运行。</p> <p>这样的设计不仅适用于语音克隆,更展示了如何从系统层面保障用户的自主权,以及如何将透明和同意变成 <strong>可执行的功能</strong>,而不仅仅是口头承诺。</p> <h2 class="relative group flex items-baseline"> <a id="技术细节" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/voice-consent-gate#%E6%8A%80%E6%9C%AF%E7%BB%86%E8%8A%82" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 技术细节 </span> </h2> <p>要构建一个包含语音同意门的基础语音克隆系统,你需要以下三部分:</p> <ol> <li>一种方法,用来生成说话人当前上下文中可用的、表达明确同意的唯一语句。</li> <li>一个 <strong>自动语音识别(ASR)系统</strong>,用于识别说话人所说的同意语句。</li> <li>一个 <strong>语音克隆的文本转语音(TTS)系统</strong>,可以接收文本和说话人的语音片段来合成新的语音。</li> </ol> <p><strong>我们的发现是:</strong> 现在很多语音克隆模型只需要一句话就能模仿说话人的声音,因此这句用于表达“同意”的句子,也可以同时作为语音克隆的输入数据。</p> <h3 class="relative group flex items-baseline"> <a id="实现方法" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/voice-consent-gate#%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%B3%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 实现方法 </span> </h3> <p><strong>关于“同意”:</strong> 在英语语音克隆系统中创建语音同意门的方式是:为说话人生成一句简短、自然、约20个单词左右的英文语句,让其朗读。这句话要明确表达对当前使用情境的知情同意。我们建议在句中明确包含“同意语句”和“模型名称”,比如:“I give my consent to use the voice cloning model with my voice(我同意使用&lt;模型名称&gt;语音克隆模型克隆我的声音)”。同时建议使用 <strong>麦克风实时录音</strong>,而不是上传音频文件,以防止使用之前录音剪辑过的语音。使用全新(从未说过的)句子也能进一步确保这个“同意”是针对当前情境、主动做出的、知情且明确的同意。</p> <p>当然,这种设计不是万无一失的。理论上,人们依然可能用其他 TTS 系统来伪造这段“同意”语音。未来的版本可以进一步尝试音频来源验证、说话人嵌入相似度分析、或通过实时录音元数据来提升验证能力。</p> <p><strong>关于“适合语音克隆的语句”部分:</strong> 已有的语音克隆研究表明,用于训练模型的语句需要具备以下几个特点:</p> <ul> <li><strong>音素多样性</strong>:语句中应包含多种元音和辅音,确保发音覆盖范围广,<a href="https://proceedings.neurips.cc/paper_files/paper/2018/file/6832a7b24bc06775d02b7406880b93fc-Paper.pdf" rel="nofollow">参考文献</a>。</li> <li><strong>语气中性或礼貌</strong>:语音应保持自然、平静或友善的语调,<a href="https://dl.acm.org/doi/10.5555/3666122.3666982" rel="nofollow">参考文献</a>,避免情绪化表达。</li> <li><strong>录音环境安静,发音自然</strong>:尽量避免背景噪音,并在说话人状态舒适时录制。</li> <li><strong>语音片段要有完整的起止</strong>:录音剪辑时不能截断词语,要保留完整的一句话,确保语音首尾清晰。</li> </ul> <p>为了实现这两个目标,在演示中我们使用语言模型自动生成一组句子:一句用于表达明确的同意,另一句则是中性内容,用于增加音素多样性(覆盖不同的元音、辅音和语调)。 每次生成时,系统会随机选择一个日常话题(如天气、美食或音乐),使句子内容丰富多样,也更自然好读,有助于录音清晰、自然,并具备良好的语音质量,同时包含明确的同意声明。 这个句子生成过程是 <strong>自动完成</strong> 的,而不是预先写好的,确保每位用户都会获得 <strong>独一无二</strong> 的句子组合,避免文本被重复使用,也确保每次录音都是针对当前会话场景所做出的具体同意。 换句话说,语言模型在每次“同意实例”中都会生成两句全新的句子:</p> <ul> <li>一句表达明确的使用同意,</li> <li>一句则用于增加语音中的音素多样性。</li> </ul> <p>比如,模型可能会生成如下内容: <em>“I give my consent to use my voice for generating audio with the model EchoVoice. The weather is bright and calm this morning.”</em></p> <p>这种做法确保了所有用于语音克隆的样本都具有 <strong>可验证的明确同意</strong>,同时也符合高质量语音合成所需的技术标准。 (注:生成句子的语言模型不必是“大型语言模型”,因为后者本身也可能涉及额外的同意问题。)</p> <p><strong>更多例子:</strong></p> <ul> <li><em>“I give my consent to use my voice for generating synthetic audio with the Chatterbox model today. My daily commute involves navigating through crowded streets on foot most days lately anyway.”</em></li> <li><em>“I give my consent to use my voice for generating audio with the model Chatterbox. After a gentle morning walk, I'm feeling relaxed and ready to speak freely now.”</em></li> <li><em>“I agree to the use of my recorded voice for audio generation with the model Chatterbox. The coffee shop outside has a pleasant aroma of freshly brewed coffee this morning.”</em></li> </ul> <h3 class="relative group flex items-baseline"> <a id="解锁语音同意门" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/voice-consent-gate#%E8%A7%A3%E9%94%81%E8%AF%AD%E9%9F%B3%E5%90%8C%E6%84%8F%E9%97%A8" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 解锁语音同意门 </span> </h3> <p>当说话人读出的语句与系统生成的文本完全匹配后,语音克隆系统便可启动,并使用这段“同意”语音作为训练输入。</p> <p>目前已有几种实现方式,当然我们也很欢迎更多建议:</p> <ul> <li><strong>演示中提供的方式:</strong> 同意门一旦开启,系统就可以直接进入语音克隆阶段,用户可输入任意文本,生成对应的合成语音。此时,模型会直接利用“同意”语音作为训练数据。</li> <li><strong>可选方案一:</strong> 修改演示中的代码,使系统可以接受多个语音文件来建模用户的声音——比如用户授权使用网络上存在的录音。此时提示语和同意语句也需相应调整。</li> <li><strong>可选方案二:</strong> 将同意录音保存下来,以便后续系统中用于生成任意语句。这可以通过 <code>huggingface_hub</code> 上传功能实现,<a href="https://huggingface.co/docs/huggingface_hub/en/guides/upload">相关指南在此</a>。同样需要根据使用场景调整提示语和同意内容。</li> </ul> <blockquote class="tip"> <p></p> <h3 class="relative group flex items-baseline"> <a id="点此查看我们的演示!" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/voice-consent-gate#%E7%82%B9%E6%AD%A4%E6%9F%A5%E7%9C%8B%E6%88%91%E4%BB%AC%E7%9A%84%E6%BC%94%E7%A4%BA%EF%BC%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> <a href="https://huggingface.co/spaces/society-ethics/RepeatAfterMe">点此查看我们的演示!</a> </span> </h3> <p>你可以复制代码,自行调整使用。</p> </blockquote> <p>该代码是模块化的,可以根据项目需求进行裁剪和改写。我们也正在持续优化系统的稳健性与安全性,欢迎提出改进建议。</p> <p>只要负责任地使用,这项技术并不一定是“幽灵般”的存在。它完全可以成为人与机器之间 <strong>相互尊重的协作工具</strong> ——没有幽灵上身,只有良好规范的技术实践。🎃</p>

2025/10/28
阅读更多

流式数据集:效率提升 100 倍

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/streaming-datasets.md">在 GitHub 上更新</a></div> <h2 class="relative group flex items-baseline"> <a id="快速了解(tldr)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E5%BF%AB%E9%80%9F%E4%BA%86%E8%A7%A3%EF%BC%88tldr%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 快速了解(TLDR) </span> </h2> <blockquote> <p>现在只需一行代码,就能通过 <code>load_dataset('dataset', streaming=True)</code> 以流式方式加载数据集,无需下载!</p> <p>无需复杂配置、不占磁盘空间、不再担心 “磁盘已满” 或 429 请求过多错误,立即开始训练 TB 级数据集! 性能非常强劲:在 64×H100、256 个并发 worker 环境下,流式加载速度甚至超过本地 SSD! 我们优化后的流式系统:请求数减少 100 倍 → 数据解析速度提升 10 倍 → 样本处理速度翻倍 → 即使在 256 个并发 worker 下也 0 崩溃。</p> </blockquote> <img src="https://imgproxy.citrusreader.com/4oGePPfq-XowfQ_GZ7ppjk8cjLugwrvBfdxwiK6Sl7Q/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vc3RyZWFtaW5nLWRhcmsuZ2lm" width="800" height="auto" alt="数据流式加载可视化" referrerpolicy="no-referrer"> <p>在机器学习中,特别是在处理 TB 级别的数据时,数据加载一直是个大难题。我们自己在训练 <a href="https://huggingface.co/blog/smollm3">SmolLM3</a> 时也深有体会,有段时间每次训练前都得等上 3 小时下载数据。</p> <p>虽然 <code>datasets</code> 库早就支持流式加载,但在大规模训练中依然面临瓶颈。今天,这一切都变了 🔥。我们花了几个月优化后端,全面提升流式数据集的速度与效率。</p> <p>那我们到底做了哪些优化?⤵️</p> <h2 class="relative group flex items-baseline"> <a id="一样简单的-api,更强大的性能" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E4%B8%80%E6%A0%B7%E7%AE%80%E5%8D%95%E7%9A%84-api%EF%BC%8C%E6%9B%B4%E5%BC%BA%E5%A4%A7%E7%9A%84%E6%80%A7%E8%83%BD" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 一样简单的 API,更强大的性能 </span> </h2> <p>首先最重要的一点:<strong>改进后的接口依然兼容原来的用法</strong>。你只需要加上 <code>streaming=True</code>,就能流式加载 Hugging Face 上的任意数据集,依旧简单直接。🚀</p> <pre><code class="language-python"><span class="hljs-keyword">from</span> datasets <span class="hljs-keyword">import</span> load_dataset <span class="hljs-comment"># 以流式方式加载数据集,而非先下载</span> dataset = load_dataset(<span class="hljs-string">"HuggingFaceM4/FineVisionMax"</span>, split=<span class="hljs-string">"train"</span>, streaming=<span class="hljs-literal">True</span>) <span class="hljs-comment"># 获取第一个样本</span> <span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(<span class="hljs-built_in">iter</span>(dataset))) </code></pre> <p>全球成千上万的 AI 开发者每天都在使用 <code>datasets</code>,现在他们无需改动任何代码,就能直接享受到更高的性能。</p> <h2 class="relative group flex items-baseline"> <a id="问题挑战:大规模流式加载" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E9%97%AE%E9%A2%98%E6%8C%91%E6%88%98%EF%BC%9A%E5%A4%A7%E8%A7%84%E6%A8%A1%E6%B5%81%E5%BC%8F%E5%8A%A0%E8%BD%BD" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 问题挑战:大规模流式加载 </span> </h2> <p>流式加载一直是快速了解数据集的好方法,但在训练模型时,大多数人仍然选择将数据预先下载到本地,或使用 S3 等云存储——我们在训练 <a href="https://huggingface.co/blog/smolvlm2">SmolVLM</a> 时也是这么做的。</p> <p>我们希望改变这种情况,于是在开发 <a href="https://github.com/huggingface/nanoVLM" rel="nofollow">nanoVLM</a> 时,尝试直接从 Hugging Face Hub 进行流式读取。</p> <p>但很快就遇到一个严重问题:<strong>一次测试运行在不到一分钟的时间内发出了超过 10 万个请求,结果我们的 IP 被 Hub 屏蔽了!</strong>😅</p> <p>问题的根源在于:<strong>每个 <code>DataLoader</code> 的 worker 都在独立初始化数据集</strong>,这导致大量冗余请求,形成了“请求风暴”,其中大部分其实是没必要的。</p> <p>于是我们对启动逻辑进行了深度优化,<strong>最终将启动请求量减少了 100 倍</strong>。总体性能提升如下:</p> <ul> <li><strong>数据文件解析速度:提升 10 倍</strong></li> <li><strong>启动请求效率:提高最多 100 倍</strong></li> <li><strong>流式速度:提升最多 2 倍</strong></li> <li><strong>在途请求效率:提升最多 2 倍</strong></li> </ul> <h2 class="relative group flex items-baseline"> <a id="技术揭秘:我们具体改了什么?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E6%8A%80%E6%9C%AF%E6%8F%AD%E7%A7%98%EF%BC%9A%E6%88%91%E4%BB%AC%E5%85%B7%E4%BD%93%E6%94%B9%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 技术揭秘:我们具体改了什么? </span> </h2> <p>我们主要优化了两个阶段:<strong>启动阶段</strong> 和 <strong>流式加载阶段</strong>。</p> <h3 class="relative group flex items-baseline"> <a id="1-启动优化-⚡️" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#1-%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96-%E2%9A%A1%EF%B8%8F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 1. 启动优化 ⚡️ </span> </h3> <p>初始的数据文件解析阶段会触发大量请求。我们进行了以下两项关键优化:</p> <ul> <li><p><strong>持久化数据文件缓存</strong>:现在所有 <code>DataLoader</code> worker 会共享数据文件列表缓存。第一个 worker 从 Hub 获取文件列表,其余 worker 直接从本地缓存中读取,从而<strong>几乎完全消除启动阶段的请求</strong>,大幅缩短加载时间,彻底告别“请求风暴”。</p> </li> <li><p><strong>优化文件解析逻辑</strong>:我们精简了初始 worker 向 Hub 请求文件列表的 API 调用数量,将多个请求进行打包处理,进一步<strong>降低启动延迟</strong>。</p> </li> </ul> <h3 class="relative group flex items-baseline"> <a id="2-流式加载优化-🏎️" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#2-%E6%B5%81%E5%BC%8F%E5%8A%A0%E8%BD%BD%E4%BC%98%E5%8C%96-%F0%9F%8F%8E%EF%B8%8F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 2. 流式加载优化 🏎️ </span> </h3> <p>为了提升训练过程中的流式吞吐量,我们新增了两个关键功能:</p> <ul> <li><p><strong>Parquet 数据预取(Prefetching)</strong>:我们为 Parquet 格式的数据集启用了预取功能。这意味着,在模型处理当前数据块的同时,<code>datasets</code> 库会在后台<strong>提前加载下一块数据</strong>。这样可以让整个数据管道始终保持“满负荷”,确保 GPU 不会因等待数据而处于空闲状态,大大提升训练效率。</p> </li> <li><p><strong>可配置缓冲机制(Buffering)</strong>:针对高级用户,我们开放了缓冲区的配置参数,支持自定义设置<strong>预取数量和数据块大小</strong>,方便根据自身硬件和网络情况进行 I/O 优化。</p> </li> </ul> <p>以下是如何将默认流式请求大小从 32MiB 提升到 128MiB,并启用预取的示例代码:</p> <pre><code class="language-python"><span class="hljs-keyword">import</span> pyarrow <span class="hljs-keyword">import</span> pyarrow.dataset fragment_scan_options = pyarrow.dataset.ParquetFragmentScanOptions( cache_options=pyarrow.CacheOptions( prefetch_limit=<span class="hljs-number">1</span>, range_size_limit=<span class="hljs-number">128</span> &lt;&lt; <span class="hljs-number">20</span> ), ) ds = load_dataset(parquet_dataset_id, streaming=<span class="hljs-literal">True</span>, fragment_scan_options=fragment_scan_options) </code></pre> <p>通过这些优化,你的数据加载速度可以提升一倍,训练效率更高!</p> <h2 class="relative group flex items-baseline"> <a id="为什么比-s3-还快?背后是-xet-技术" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%94-s3-%E8%BF%98%E5%BF%AB%EF%BC%9F%E8%83%8C%E5%90%8E%E6%98%AF-xet-%E6%8A%80%E6%9C%AF" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为什么比 S3 还快?背后是 Xet 技术 </span> </h2> <p>Hugging Face 使用了 <strong>Xet 存储系统</strong>:这是一种去重式存储方案,上传和下载速度极快。与传统远程存储不同,Xet 会跳过重复数据,只传输独特内容。</p> <p>比如,在 Hugging Face 上传大型数据集时,Xet 的去重机制大幅减少了数据传输量,上传更快;数据一上传完,就可以立即开始流式读取。</p> <p>对于 Parquet 文件,Xet 利用 <a href="https://huggingface.co/blog/parquet-cdc">Parquet 内容定义切块(CDC)</a> 来实现去重,进一步加快传输速度。</p> <p>此外,我们还推出了 <code>pyspark_huggingface</code> 包,支持 Spark 直接读写 HF 数据集,内置对 Parquet CDC 和 Xet 的支持,大幅加快大数据处理。</p> <hr> <h2 class="relative group flex items-baseline"> <a id="想自定义流式管道?可以!" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E6%83%B3%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B5%81%E5%BC%8F%E7%AE%A1%E9%81%93%EF%BC%9F%E5%8F%AF%E4%BB%A5%EF%BC%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 想自定义流式管道?可以! </span> </h2> <p>有些数据格式 <code>datasets</code> 库还不支持,或者你希望获得更高的控制权,我们也提供了强大的自定义流式能力。</p> <p><code>huggingface_hub</code> 库中的 <a href="https://huggingface.co/docs/huggingface_hub/guides/hf_file_system">HfFileSystem</a> 可高效读取远程数据集文件:</p> <pre><code class="language-python"><span class="hljs-keyword">from</span> huggingface_hub <span class="hljs-keyword">import</span> HfFileSystem path = <span class="hljs-string">f"hf://datasets/<span class="hljs-subst">{dataset_id}</span>/<span class="hljs-subst">{path_in_repo}</span>"</span> <span class="hljs-keyword">with</span> HfFileSystem().<span class="hljs-built_in">open</span>(path) <span class="hljs-keyword">as</span> f: <span class="hljs-comment"># 使用 .read() 或 .readline() 流式读取数据</span> <span class="hljs-comment"># 也支持 .seek() 进行随机访问</span> </code></pre> <p>将 <code>HfFileSystem</code> 传入 PyTorch 的 <code>DataLoader</code> 时,会<strong>复用 <code>.ls()</code> 和 <code>.glob()</code> 的缓存结果</strong>,从而<strong>避免在列举数据文件时产生额外的网络请求</strong>,进一步提升流式加载的效率和稳定性。</p> <h2 class="relative group flex items-baseline"> <a id="极限测试:我们把它用在-nanovlm-上了!" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E6%9E%81%E9%99%90%E6%B5%8B%E8%AF%95%EF%BC%9A%E6%88%91%E4%BB%AC%E6%8A%8A%E5%AE%83%E7%94%A8%E5%9C%A8-nanovlm-%E4%B8%8A%E4%BA%86%EF%BC%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 极限测试:我们把它用在 nanoVLM 上了! </span> </h2> <p>目前我们正在使用这些流式优化功能训练下一代 SmolVLM 模型。得益于新改进,流式加载比我们集群上的多层硬盘系统还要快,<strong>几乎等同于从本地 SSD 读取数据的速度</strong>!</p> <p>过去,为了避免慢速网络,我们还要把数据拷贝到本地 SSD——整个过程花费 3 小时。而现在,直接流式加载,训练马上开始!</p> <p>更多细节请看:<a href="https://github.com/huggingface/nanoVLM" rel="nofollow">nanoVLM GitHub</a></p> <h2 class="relative group flex items-baseline"> <a id="快速上手,立见成效" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/streaming-datasets#%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B%EF%BC%8C%E7%AB%8B%E8%A7%81%E6%88%90%E6%95%88" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 快速上手,立见成效 </span> </h2> <p>这些强大的新功能已经集成到 <code>datasets</code> 和 <code>huggingface_hub</code> 库中。想要体验全新的流式加载性能,只需升级你的库版本,并查阅<a href="https://huggingface.co/docs/datasets/stream">官方文档</a>即可开始使用:</p> <pre><code class="language-bash">pip install --upgrade datasets huggingface_hub </code></pre> <p>为庆祝这一更新,我们已将 FineVision 所有数据源合并并预先打乱成一个统一数据集:<a href="https://huggingface.co/datasets/HuggingFaceM4/FineVisionMax">FineVisionMax</a>。你可以直接用它来训练 VLM 模型,无需手动处理多个数据集!</p> <pre><code class="language-python"><span class="hljs-keyword">from</span> datasets <span class="hljs-keyword">import</span> load_dataset <span class="hljs-comment"># 以流式方式加载数据集,而非先下载</span> dataset = load_dataset(<span class="hljs-string">"HuggingFaceM4/FineVisionMax"</span>, split=<span class="hljs-string">"train"</span>, streaming=<span class="hljs-literal">True</span>) <span class="hljs-comment"># 获取第一个样本</span> <span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(<span class="hljs-built_in">iter</span>(dataset))) </code></pre> <p>想了解我们是如何大规模运行的?欢迎查看:<a href="https://github.com/huggingface/nanoVLM" rel="nofollow">nanoVLM 项目</a></p> <p>祝你流式加载愉快!🤗</p>

2025/10/27
阅读更多

huggingface_hub v1.0:开源机器学习基础五周年回顾

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/huggingface-hub-v1.md">在 GitHub 上更新</a></div> <p></p><strong>简要总结:</strong> 经过五年的持续开发,<code>huggingface_hub</code> 发布 v1.0 正式版!这一里程碑标志着这个库的成熟与稳定。它已成为 Python 生态中支撑 <strong>20 万个依赖库</strong> 的核心组件,并提供访问超过 <strong>200 万公开模型</strong>、<strong>50 万公开数据集</strong> 和 <strong>100 万 Space 应用</strong> 的基础能力。本次更新包含为支持未来十年开源机器学习生态而做出的重大变更,由近 300 位贡献者和数百万用户共同推动发展。<p></p> <p><strong>🚀 强烈建议尽快升级至 v1.0,以体验更优性能和全新功能。</strong></p> <pre><code class="language-bash">pip install --upgrade huggingface_hub </code></pre> <p>此次重大版本更新包括以下内容:</p> <ul> <li>使用 <code>httpx</code> 作为新后端请求库;</li> <li>全新设计的 <code>hf</code> 命令行工具(取代已弃用的 <code>huggingface-cli</code>),采用 Typer 构建,功能更加丰富;</li> <li>文件传输全面迁移至 <code>hf_xet</code>,彻底淘汰旧的 <code>hf_transfer</code> 工具。</li> </ul> <p>查看完整的 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v1.0.0" rel="nofollow">v1.0 发布说明</a></p> <blockquote class="tip"> <p>我们尽可能确保 v1.0.0 与旧版本兼容。大多数机器学习库无需修改即可兼容 v0.x 和 v1.x。主要例外是 <code>transformers</code>:v4 版本依赖 v0.x,计划中的 v5 将转向 v1.x。查看此 <a href="https://github.com/huggingface/huggingface_hub/issues/3340" rel="nofollow">issue</a> 获取详细的库兼容性表。</p> </blockquote> <h2 class="relative group flex items-baseline"> <a id="背后的故事" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E8%83%8C%E5%90%8E%E7%9A%84%E6%95%85%E4%BA%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 背后的故事 </span> </h2> <p>每个主流库背后都有一段故事。<code>huggingface_hub</code> 的故事始于一个简单的想法:<strong>如果共享机器学习模型像在 GitHub 上分享代码一样容易,会怎样?</strong></p> <p>在 Hugging Face Hub 的早期阶段,研究人员和开发者常常面临一个困扰: 训练一个先进的模型不仅耗时、耗资源,而且在训练完成后,模型往往“被困”在个人电脑里,只能通过不稳定的 Google Drive 链接进行分享。 这导致社区重复造轮子,资源浪费严重,协作效率极低。</p> <p>为了解决这一问题,Hugging Face Hub 应运而生。最初,它的功能很简单,只是用于共享和托管与 <code>transformers</code> 库兼容的模型检查点。而与 Hub 交互的全部 Python 逻辑代码,也都内置在 <code>transformers</code> 库中,其他库无法复用这些功能。</p> <p>直到 2020 年底,我们推出了 <code>huggingface_hub</code> 的首个版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.0.1" rel="nofollow">v0.0.1</a>,它的初衷是:将原本封装在 <code>transformers</code> 库中的内部逻辑独立出来,构建一个专用库,用于统一访问和共享 Hugging Face Hub 上的机器学习模型与数据集。最早的版本非常简洁,它只是一个 Git 操作的封装工具,用于下载文件和管理仓库。但五年过去,历经 35+ 个版本迭代,<code>huggingface_hub</code> 已远远超越最初的设想。</p> <p>让我们一起来回顾这段发展历程。</p> <div class="flex justify-center"> <img class="block dark:hidden" src="https://imgproxy.citrusreader.com/UYzNxb_VLofj_JNcJyh1eYw9MxCN4uS0ir3jgXFgsXI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9odWdnaW5nZmFjZS1odWItdjEvdGltZWxpbmUtd2hpdGUuZ2lm" referrerpolicy="no-referrer"> <img class="hidden dark:block" src="https://imgproxy.citrusreader.com/Uu6D1AsyKvWtbHP8S6_tgGyiEu3RZXV-MiMSjH478qQ/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9odWdnaW5nZmFjZS1odWItdjEvdGltZWxpbmUtYmxhY2suZ2lm" referrerpolicy="no-referrer"> </div> <h3 class="relative group flex items-baseline"> <a id="奠基阶段(20202021)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E5%A5%A0%E5%9F%BA%E9%98%B6%E6%AE%B5%EF%BC%8820202021%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 奠基阶段(2020–2021) </span> </h3> <p>最初的几个版本为整个库打下了基础。 版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.0.8" rel="nofollow">0.0.8</a> 引入了第一个 API,通过封装 Git 命令,实现与模型仓库的交互。 接着在版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.0.17" rel="nofollow">0.0.17</a> 中,加入了基于 token 的认证机制,支持访问私有仓库并安全上传内容。 虽然这些功能看起来很基础,但它们构成了后来所有进步的基石。</p> <h3 class="relative group flex items-baseline"> <a id="重要转折:从-git-到-http(2022)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E9%87%8D%E8%A6%81%E8%BD%AC%E6%8A%98%EF%BC%9A%E4%BB%8E-git-%E5%88%B0-http%EF%BC%882022%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 重要转折:从 Git 到 HTTP(2022) </span> </h3> <p>2022 年 6 月,版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.8.1" rel="nofollow">0.8.1</a> 发布,这是 Hugging Face Hub 发展史上的一个转折点——我们引入了 HTTP Commit API。</p> <p>从此,用户无需再安装 Git 和 Git LFS,也能直接通过 HTTP 上传文件。新推出的 <code>create_commit()</code> API 极大简化了上传流程,尤其适合处理大型模型文件——这些文件过去通过 Git LFS 操作起来十分繁琐。</p> <p>此外,该版本还引入了支持 Git 结构感知的缓存机制。所有使用 <code>huggingface_hub</code> 的库(无论是官方的 transformers,还是第三方库)现在都能共享同一套缓存系统,具备显式的版本控制和文件去重功能。</p> <p>这不仅仅是一次技术优化,更是一次理念上的飞跃。 我们不再只是为 transformers 构建 Git 工具,而是在构建一套专为机器学习模型和数据打造的基础设施,面向整个机器学习生态服务。</p> <h3 class="relative group flex items-baseline"> <a id="api-能力的全面扩展(20222024)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#api-%E8%83%BD%E5%8A%9B%E7%9A%84%E5%85%A8%E9%9D%A2%E6%89%A9%E5%B1%95%EF%BC%8820222024%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> API 能力的全面扩展(2022–2024) </span> </h3> <p>随着 Hugging Face Hub 从一个模型仓库逐步发展为一个完整的平台,<code>huggingface_hub</code> 的 API 能力也不断拓展,满足更多场景需求。</p> <p>核心的仓库操作功能不断成熟,支持:</p> <ul> <li>列出文件树(list tree)</li> <li>浏览引用(refs)与提交记录(commits)</li> <li>读取文件或同步整个文件夹</li> <li>管理标签、分支和发布周期(release cycle)</li> <li>查询仓库元数据与设置 webhook,帮助团队实时响应变更</li> </ul> <p>与此同时,Hub 上的 <a href="https://huggingface.co/docs/huggingface_hub/guides/manage-spaces">Spaces</a> 功能开始崭露头角,它是一个简单却强大的方式,可以直接在 Hub 上托管和分享交互式的机器学习演示项目。<code>huggingface_hub</code> 也逐步实现了对 Spaces 的完整程序化管理能力,包括硬件资源申请、环境配置、密钥管理、文件上传等。</p> <p>为了支持模型在生产环境中的部署,我们还集成了 <a href="https://huggingface.co/docs/huggingface_hub/guides/inference_endpoints">Inference Endpoints</a>。而在 2025 年第三季度,<a href="https://huggingface.co/docs/huggingface_hub/guides/jobs">Jobs API</a> 的加入,进一步完善了 Hugging Face 的计算服务能力。</p> <p>在此过程中,社区与社交层也被提升为一等公民。现在支持:</p> <ul> <li>创建和管理 <a href="https://huggingface.co/docs/huggingface_hub/guides/community">Pull Requests 和评论</a></li> <li>查询用户与组织信息</li> <li>仓库点赞、关注、粉丝功能</li> <li>使用 <a href="https://huggingface.co/docs/huggingface_hub/guides/collections">Collections</a> 整理和分享资源合集</li> </ul> <p>同时,日常使用体验也得到了显著优化:Colab 中的无缝认证、大型文件夹上传的可靠性提升、支持断点续传等功能,使开发更加高效流畅。</p> <p>随后,在版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.28.0" rel="nofollow">v0.28.0</a> 中,我们推出了 <a href="https://huggingface.co/docs/huggingface_hub/guides/inference">推理服务提供方生态</a>。不再依赖单一的推理后端,而是与多家无服务器推理平台合作,包括 Together AI、SambaNova、Replicate、Cerebras、Groq 等,用户通过一个统一的 API 即可调用多个后端,路由透明,按请求计费,真正实现了“按需调用,轻松推理”。</p> <h3 class="relative group flex items-baseline"> <a id="ready-xet-go(20242025)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#ready-xet-go%EF%BC%8820242025%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Ready. Xet. Go!(2024–2025) </span> </h3> <p>在版本 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.30.0" rel="nofollow">v0.30.0</a> 中,我们发布了 Xet —— 一种颠覆性的 Git 大文件存储协议。</p> <p>与传统的 Git LFS(只支持文件级去重)不同,Xet 在更精细的粒度(每 64KB 为一块)进行数据去重与传输优化。当你更新一个大型模型或数据文件时,系统只会上传或下载发生变更的部分,而不是整个文件。</p> <p>这场<a href="https://huggingface.co/spaces/jsulz/ready-xet-go">大规模迁移</a> 始于 50 多万个仓库,涉及超过 20PB 的数据。但令人惊喜的是,这一迁移过程对用户是完全透明的,100% 向后兼容,无需手动干预,也没有中断现有流程。</p> <p>一年后,超过 <strong>6,000,000 个仓库</strong>、<strong>77PB+</strong> 的数据已成功迁移至 Xet 后端,带来了更快、更智能的上传与下载体验 🔥</p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/huggingface-hub-v1/xet_progress.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/qcfx_pkFeqgZCrZSvFivPQQjTSuBBzEg8bVL09IBT1k/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9odWdnaW5nZmFjZS1odWItdjEveGV0X3Byb2dyZXNzLnBuZw" alt referrerpolicy="no-referrer"></a></p> <h2 class="relative group flex items-baseline"> <a id="成长与影响力衡量" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E6%88%90%E9%95%BF%E4%B8%8E%E5%BD%B1%E5%93%8D%E5%8A%9B%E8%A1%A1%E9%87%8F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 成长与影响力衡量 </span> </h2> <p>衡量一个开源库的成长和影响力并不容易,但有时,数字本身就是最好的证明:</p> <ul> <li><strong>每月下载量达 1.135 亿次</strong>,<strong>累计下载超 16 亿次</strong>(截至 2025 年 10 月)</li> <li>提供访问 <strong>200 万+ 公共模型</strong>、<strong>50 万+ 公共数据集</strong> 和 <strong>100 万+ 公共 Spaces</strong> —— 如果包括私有仓库,总量大约翻倍</li> <li>每日活跃用户超过 <strong>6 万人</strong>,每月活跃用户超过 <strong>55 万人</strong></li> <li>被全球 <strong>20 万+ 企业</strong> 信赖使用,从初创公司到《财富》500 强企业</li> </ul> <p>但真正体现其规模的,是整个生态的广度和深度。<code>huggingface_hub</code> 已成为 GitHub 上 <strong>超过 20 万个仓库</strong> 和 PyPI 上 <strong>3,000 个软件包</strong> 的 <strong>依赖核心</strong> ,涵盖主流框架如 Keras、LangChain、PaddleOCR、ChatTTS、YOLO、Google Generative AI、Moshi、NVIDIA NeMo、Open Sora 等,还有无数小型工具与项目。Hugging Face 自家生态(如 transformers、diffusers、datasets、sentence-transformers、gradio、peft、trl 等)也都建立在其之上。</p> <p>最令人欣慰的是,这些第三方集成大多数都是自然发生的,我们并未主动推动。这正是 Hugging Face Hub 释放力量的体现——它让整个机器学习社区能够更加开放、高效地协作与创新,而它如今的广泛使用程度,也远超我们的最初预期。</p> <h2 class="relative group flex items-baseline"> <a id="面向未来十年的构建" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E9%9D%A2%E5%90%91%E6%9C%AA%E6%9D%A5%E5%8D%81%E5%B9%B4%E7%9A%84%E6%9E%84%E5%BB%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 面向未来十年的构建 </span> </h2> <p>v1.0 不只是一个版本号的跃迁,它代表的是:<strong>为未来十年开放式机器学习奠定坚实基础</strong>。我们做出的破坏性更新并非随意为之,而是出于战略考虑,为了让 <code>huggingface_hub</code> 能够应对 AI 的高速发展,并保持全球数百万开发者所依赖的稳定性与可靠性。</p> <h3 class="relative group flex items-baseline"> <a id="现代化-http-架构:httpx-与-hf_xet" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E7%8E%B0%E4%BB%A3%E5%8C%96-http-%E6%9E%B6%E6%9E%84%EF%BC%9Ahttpx-%E4%B8%8E-hf_xet" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 现代化 HTTP 架构:httpx 与 hf_xet </span> </h3> <p>v1.0 最重要的架构变更,是将底层 HTTP 请求库从 <code>requests</code> 迁移至 <a href="https://www.python-httpx.org/" rel="nofollow"><code>httpx</code></a>。这不仅是依赖项的替换,而是一次真正意义上的升级,使整个库正式迈入现代 HTTP 时代。</p> <p><strong>为什么选择 httpx?</strong> 它带来的好处非常显著:</p> <ul> <li>原生支持 HTTP/2,连接效率更高</li> <li>完整的线程安全,可在多线程间安全复用连接</li> <li>最关键的是:提供统一的同步与异步接口,彻底消除原先同步与异步推理客户端之间的微妙差异</li> </ul> <p>此次迁移的设计尽可能做到“对用户透明”,大多数用户无需做任何修改。对于使用自定义 HTTP 后端的开发者,我们提供了清晰的迁移路径,将 <code>configure_http_backend()</code> 替换为 <code>set_client_factory()</code> 或 <code>set_async_client_factory()</code>。</p> <p>同时,<code>hf_xet</code> 现已成为 Hub 上传和下载文件的默认工具包,完全取代此前的可选方案 <code>hf_transfer</code>,后者已被彻底移除。</p> <h3 class="relative group flex items-baseline"> <a id="mcp-与-tiny-agents:让智能体开发触手可及" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#mcp-%E4%B8%8E-tiny-agents%EF%BC%9A%E8%AE%A9%E6%99%BA%E8%83%BD%E4%BD%93%E5%BC%80%E5%8F%91%E8%A7%A6%E6%89%8B%E5%8F%AF%E5%8F%8A" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> MCP 与 Tiny-Agents:让智能体开发触手可及 </span> </h3> <p>在 <a href="https://github.com/huggingface/huggingface_hub/releases/tag/v0.32.0" rel="nofollow">v0.32.0</a> 中,我们引入了 <strong>Model Context Protocol(模型上下文协议,MCP)集成</strong> 和 <strong>tiny-agents 工具链</strong>,这从根本上改变了构建 AI Agent 的方式。曾经需要复杂框架集成的任务,如今只需大约 70 行 Python 代码即可完成。</p> <p><a href="https://huggingface.co/docs/huggingface_hub/package_reference/mcp"><code>MCPClient</code></a> 提供了一个标准化接口,使 AI Agent 能够轻松与各种工具进行交互;而 <code>tiny-agents</code> CLI 工具则允许你直接从 Hub 启动 Agent。你可以连接本地或远程 MCP 服务器,将任意 Gradio Space 用作工具,并构建出自然、流畅、响应迅速的对话式智能体。</p> <p>所有这些,都是在我们现有的 <code>InferenceClient</code> 以及其支持的多家推理服务商的基础上构建的。我们坚信 Agent 是未来,而 <code>huggingface_hub</code> 将持续提供这些构建 AI 工具的基础模块,助力开发者快速落地创新想法。</p> <h3 class="relative group flex items-baseline"> <a id="面向现代工作流的全功能命令行工具" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E9%9D%A2%E5%90%91%E7%8E%B0%E4%BB%A3%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%9A%84%E5%85%A8%E5%8A%9F%E8%83%BD%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B7%A5%E5%85%B7" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 面向现代工作流的全功能命令行工具 </span> </h3> <p>Hugging Face 的 CLI 工具已经从一个简单的命令行工具,发展为一个 <strong>功能全面的机器学习操作接口</strong>。全新设计的 <code>hf</code> 命令取代了老旧的 <code>huggingface-cli</code>,采用现代化的“资源-动作”模式:</p> <ul> <li><code>hf auth login</code>:用户认证</li> <li><code>hf download</code> 和 <code>hf upload</code>:文件上传与下载</li> <li><code>hf repo</code>:仓库管理</li> <li><code>hf cache ls</code> 和 <code>hf cache rm</code>:缓存管理</li> <li><code>hf jobs run</code>:运行云端计算任务</li> </ul> <p>CLI 提供了 <a href="https://huggingface.co/docs/huggingface_hub/installation#install-the-hugging-face-cli">沙箱式安装器</a>,可以在不破坏现有开发环境的前提下快速安装或升级:</p> <pre><code class="language-bash"><span class="hljs-comment"># macOS 或 Linux</span> curl -LsSf https://hf.co/cli/install.sh | sh <span class="hljs-comment"># Windows</span> powershell -ExecutionPolicy ByPass -c <span class="hljs-string">"irm https://hf.co/cli/install.ps1 | iex"</span> </code></pre> <p>CLI 还支持命令自动补全,并在各大主流平台上都能顺利运行。如今的 Hugging Face CLI,已经具备与现代开发工具媲美的体验和易用性。</p> <h3 class="relative group flex items-baseline"> <a id="为未来清理技术债" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E4%B8%BA%E6%9C%AA%E6%9D%A5%E6%B8%85%E7%90%86%E6%8A%80%E6%9C%AF%E5%80%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 为未来清理技术债 </span> </h3> <p>在 v1.0 中,我们移除了部分阻碍未来发展的旧功能和用法:</p> <ul> <li>基于 Git 的 <code>Repository</code> 类已被移除。</li> <li>HTTP 接口如 <code>upload_file()</code> 和 <code>create_commit()</code> 变得更简洁、更稳定,也更适应现代化工作流。</li> <li><code>HfFolder</code> 的 token 管理方式已被显式的 <code>login()</code>、<code>logout()</code> 和 <code>get_token()</code> 函数所取代,使用方式更直观。</li> <li>原有的 <code>InferenceApi</code> 类被功能更完善的 <code>InferenceClient</code> 替代。</li> <li>文件传输工具 <code>hf_transfer</code> 被彻底淘汰,现已由全新的二进制工具包 <code>hf_xet</code> 完全接管。</li> </ul> <p>这些变更并非仓促决策,我们在数月前就已发布弃用通知,附带清晰的迁移指引。最终目标是打造一个 <strong>更清晰、更易维护</strong> 的代码库,让我们能够集中精力开发面向未来的新特性,而不是继续兼容过时的实现方式。</p> <h3 class="relative group flex items-baseline"> <a id="迁移指南" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E8%BF%81%E7%A7%BB%E6%8C%87%E5%8D%97" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 迁移指南 </span> </h3> <p>我们理解,破坏性更新可能会对现有项目造成困扰。正因如此,我们投入了大量精力,尽可能让迁移过程顺畅无痛。官方的 <a href="https://huggingface.co/docs/huggingface_hub/concepts/migration">迁移指南</a> 提供了每项变更的 <strong>逐步说明</strong>,并解释了背后的原因。</p> <p>最重要的是,我们在可能的地方 <strong>保留了向后兼容性</strong>。例如 <code>HfHubHttpError</code> 同时继承了旧版 <code>requests</code> 和新版 <code>httpx</code> 的 <code>HTTPError</code> 异常类,确保原有错误处理逻辑依然生效。</p> <p>从 v1.0 起,我们将<strong>全面聚焦新版</strong>的开发与维护,确保为社区提供更高性能、更丰富功能和更完善的工具。旧版(v0.*)仍可在 PyPI 下载,但今后只会进行安全性补丁更新,不再添加新功能。</p> <blockquote class="tip"> <p>我们尽力确保 <code>huggingface_hub</code> v1.0.0 与旧版兼容。在实际使用中,大多数机器学习库在 v0.x 与 v1.x 之间都能无缝切换。主要例外是 <code>transformers</code>:其 v4 版本明确依赖 v0.x,而即将发布的 v5 将改为依赖 v1.x。想了解各主流库的兼容情况,请参考这个 <a href="https://github.com/huggingface/huggingface_hub/issues/3340" rel="nofollow">兼容性汇总表</a>。</p> </blockquote> <h2 class="relative group flex items-baseline"> <a id="特别致谢" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/huggingface-hub-v1#%E7%89%B9%E5%88%AB%E8%87%B4%E8%B0%A2" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 特别致谢 </span> </h2> <p>感谢 280 多位为本库贡献代码、文档、翻译和社区支持的开发者们!</p> <p>同时也感谢 Hugging Face 社区提供的反馈、Bug 报告与建议,这些都帮助我们不断完善产品。</p> <p>最后,衷心感谢广大用户 —— 无论是独立开发者还是大型企业 —— 感谢你们信任 <code>huggingface_hub</code>,让它成为你们工作流程的一部分。是你们的支持激励我们不断前行。</p> <p>如果你喜欢这个项目,欢迎到 <a href="https://github.com/huggingface/huggingface_hub" rel="nofollow">GitHub 点个星 ⭐</a>,支持我们继续建设开源机器学习的未来!</p> <p>五年已过,但一切才刚刚开始!</p>

2025/10/27
阅读更多

LeRobot v0.4.0:全面提升开源机器人的学习能力

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/lerobot-release-v040.md">在 GitHub 上更新</a></div> <p></p>我们非常高兴地宣布,LeRobot 迎来一系列重大升级,让开源的机器人学习比以往更强大、更可扩展、也更易用!从重构的数据集到灵活的编辑工具、新的仿真环境,以及面向硬件的全新插件系统,LeRobot 正在持续演进,以满足前沿具身智能(Embodied AI)不断发展的需求。<p></p> <h2 class="relative group flex items-baseline"> <a id="简要总结" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E7%AE%80%E8%A6%81%E6%80%BB%E7%BB%93" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 简要总结 </span> </h2> <p>LeRobot v0.4.0 为开源机器人领域带来重要升级:引入可扩展的 Datasets v3.0、强大的新 VLA(视觉-语言-动作)模型如 PI0.5 与 GR00T N1.5,以及全新的插件系统,简化硬件集成。该版本还新增对 LIBERO 与 Meta-World 仿真的支持、简化多 GPU 训练,并上线全新的 Hugging Face 机器人学习课程。</p> <h2 class="relative group flex items-baseline"> <a id="目录" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E7%9B%AE%E5%BD%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 目录 </span> </h2> <ul> <li>[LeRobot v0.4.0:全面提升开源机器人的学习能力](#LeRobot v0.4.0:全面提升开源机器人的学习能力)</li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E7%AE%80%E8%A6%81%E6%80%BB%E7%BB%93" rel="nofollow">简要总结</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%95%B0%E6%8D%AE%E9%9B%86%E4%B8%BA%E4%B8%8B%E4%B8%80%E6%B3%A2%E5%A4%A7%E8%A7%84%E6%A8%A1%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E5%81%9A%E5%A5%BD%E5%87%86%E5%A4%87" rel="nofollow">数据集:为下一波大规模机器人学习做好准备</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#datasets-v30-%E6%9C%89%E4%BD%95%E6%96%B0%E5%8F%98%E5%8C%96" rel="nofollow">Datasets v3.0 有何新变化?</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%96%B0%E7%89%B9%E6%80%A7%E6%95%B0%E6%8D%AE%E9%9B%86%E7%BC%96%E8%BE%91%E5%B7%A5%E5%85%B7" rel="nofollow">新特性:数据集编辑工具!</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E4%BB%BF%E7%9C%9F%E7%8E%AF%E5%A2%83%E6%89%A9%E5%B1%95%E4%BD%A0%E7%9A%84%E8%AE%AD%E7%BB%83%E5%9C%BA" rel="nofollow">仿真环境:扩展你的训练场</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#libero-%E6%94%AF%E6%8C%81" rel="nofollow">LIBERO 支持</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#meta-world-%E9%9B%86%E6%88%90" rel="nofollow">Meta-World 集成</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E4%BB%A3%E7%A0%81%E5%BA%93%E4%BA%BA%E4%BA%BA%E5%8F%AF%E7%94%A8%E7%9A%84%E5%BC%BA%E5%8A%9B%E5%B7%A5%E5%85%B7" rel="nofollow">代码库:人人可用的强力工具</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%85%A8%E6%96%B0%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86-pipeline" rel="nofollow">全新的数据处理 Pipeline</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%A4%9A-gpu-%E8%AE%AD%E7%BB%83%E6%9B%B4%E7%AE%80%E5%8D%95" rel="nofollow">多 GPU 训练更简单</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E7%AD%96%E7%95%A5%E9%87%8A%E6%94%BE%E5%BC%80%E6%94%BE%E4%B8%96%E7%95%8C%E6%B3%9B%E5%8C%96%E8%83%BD%E5%8A%9B" rel="nofollow">策略:释放开放世界泛化能力</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#pi0-%E4%B8%8E-pi05" rel="nofollow">PI0 与 PI0.5</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#gr00t-n15" rel="nofollow">GR00T N1.5</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%BC%95%E9%A2%86%E7%A1%AC%E4%BB%B6%E9%9B%86%E6%88%90%E6%96%B0%E7%BA%AA%E5%85%83" rel="nofollow">机器人:插件系统引领硬件集成新纪元</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%A0%B8%E5%BF%83%E4%BC%98%E5%8A%BF" rel="nofollow">核心优势</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#reachy-2-%E9%9B%86%E6%88%90" rel="nofollow">Reachy 2 集成</a></li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%89%8B%E6%9C%BA%E9%9B%86%E6%88%90" rel="nofollow">手机集成</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#hugging-face-%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E8%AF%BE%E7%A8%8B" rel="nofollow">Hugging Face 机器人学习课程</a><ul> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%B7%B1%E5%85%A5%E8%AE%B2%E8%A7%A3%E7%8E%B0%E4%BB%A3%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B" rel="nofollow">深入讲解:现代机器人学习教程</a></li> </ul> </li> <li><a href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%9B%A2%E9%98%9F%E6%80%BB%E7%BB%93" rel="nofollow">团队总结</a></li> </ul> <h2 class="relative group flex items-baseline"> <a id="数据集:为下一波大规模机器人学习做好准备" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%95%B0%E6%8D%AE%E9%9B%86%EF%BC%9A%E4%B8%BA%E4%B8%8B%E4%B8%80%E6%B3%A2%E5%A4%A7%E8%A7%84%E6%A8%A1%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E5%81%9A%E5%A5%BD%E5%87%86%E5%A4%87" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 数据集:为下一波大规模机器人学习做好准备 </span> </h2> <p>我们彻底重构了数据集基础设施,推出 <strong>LeRobotDataset v3.0</strong>,采用全新的分块式 Episode 格式与流式读取能力。这对于处理超大规模数据集(如 <a href="https://huggingface.co/collections/lerobot/open-x-embodiment">OXE</a>(Open X Embodiment)与 <a href="https://huggingface.co/datasets/lerobot/droid_1.0.1">Droid</a>)是一次范式跃迁,带来前所未有的效率与可扩展性。</p> <h3 class="relative group flex items-baseline"> <a id="datasets-v30-有何新变化?" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#datasets-v30-%E6%9C%89%E4%BD%95%E6%96%B0%E5%8F%98%E5%8C%96%EF%BC%9F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Datasets v3.0 有何新变化? </span> </h3> <ul> <li><strong>分块式 Episodes,面向超大规模</strong>:新格式支持 OXE 量级(&gt; 400 GB)的数据集,显著提升可扩展性。</li> <li><strong>高效视频存储与流式读取</strong>:更快的加载速度与顺畅的视频数据流式访问。</li> <li><strong>统一的 Parquet 元数据</strong>:告别分散的 JSON!所有 Episode 的元数据现统一存放于结构化的 Parquet 文件中,便于管理与访问。</li> <li><strong>更快的加载与更好的性能</strong>:显著缩短数据集初始化时间,内存使用更高效。</li> </ul> <p>我们还提供了转换脚本,帮助你将现有 v2.1 数据集一键迁移到新的 v3.0 格式,确保平滑过渡。更多细节可阅读我们此前的 <a href="https://huggingface.co/blog/lerobot-datasets-v3">博客文章</a>。开源机器人的学习能力持续升级中!</p> <h3 class="relative group flex items-baseline"> <a id="新特性:数据集编辑工具!" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%96%B0%E7%89%B9%E6%80%A7%EF%BC%9A%E6%95%B0%E6%8D%AE%E9%9B%86%E7%BC%96%E8%BE%91%E5%B7%A5%E5%85%B7%EF%BC%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 新特性:数据集编辑工具! </span> </h3> <p>使用 LeRobot 数据集从未如此轻松!我们新增了一套强大的数据集灵活编辑工具。</p> <p>借助全新的命令行工具 <code>lerobot-edit-dataset</code>,你可以:</p> <ul> <li>从现有数据集中删除指定的 Episodes。</li> <li>按比例或 Episode 索引拆分数据集。</li> <li>轻松添加或移除特征字段。</li> <li>将多个数据集合并为一个统一数据集。</li> </ul> <pre><code class="language-bash"><span class="hljs-comment"># 将多个数据集合并为单一数据集</span> lerobot-edit-dataset \ --repo_id lerobot/pusht_merged \ --operation.type merge \ --operation.repo_ids <span class="hljs-string">"['lerobot/pusht_train', 'lerobot/pusht_val']"</span> <span class="hljs-comment"># 删除部分 episodes 并保存为新数据集(保留原数据集)</span> lerobot-edit-dataset \ --repo_id lerobot/pusht \ --new_repo_id lerobot/pusht_after_deletion \ --operation.type delete_episodes \ --operation.episode_indices <span class="hljs-string">"[0, 2, 5]"</span> </code></pre> <p>这些工具将大幅简化你的工作流,让你以前所未有的方式策划与优化机器人数据集。更多详情请查阅 <a href="https://huggingface.co/docs/lerobot/using_dataset_tools">文档</a>!</p> <h2 class="relative group flex items-baseline"> <a id="仿真环境:扩展你的训练场" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E4%BB%BF%E7%9C%9F%E7%8E%AF%E5%A2%83%EF%BC%9A%E6%89%A9%E5%B1%95%E4%BD%A0%E7%9A%84%E8%AE%AD%E7%BB%83%E5%9C%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 仿真环境:扩展你的训练场 </span> </h2> <p>我们持续扩展 LeRobot 的仿真能力,为你的机器人策略提供更丰富、更多样化的训练环境。</p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot-blog/release-v0.4.0/lerobot-libero-groot-v040.gif" rel="nofollow"><img src="https://imgproxy.citrusreader.com/SmTduhH0ul2AJGzuiksq-M2jFM3RqL_Qkex67XG1iW0/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vbGVyb2JvdC1ibG9nL3JlbGVhc2UtdjAuNC4wL2xlcm9ib3QtbGliZXJvLWdyb290LXYwNDAuZ2lm" alt="libero-demo" referrerpolicy="no-referrer"></a></p> <h3 class="relative group flex items-baseline"> <a id="libero-支持" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#libero-%E6%94%AF%E6%8C%81" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> LIBERO 支持 </span> </h3> <p>LeRobot 现已正式支持 <a href="https://libero-project.github.io/intro.html" rel="nofollow">LIBERO</a>——这是 VLA(视觉-语言-动作)策略中规模最大的开源基准之一,涵盖超过 130 个任务!这一步为打造 VLA 策略的首选评测枢纽奠定了基础,提供便捷的集成方式与统一的评测配置。</p> <p>前往查看 <a href="https://huggingface.co/datasets/HuggingFaceVLA/libero">LIBERO 数据集</a> 与我们的 <a href="https://huggingface.co/docs/lerobot/en/libero">文档</a> 开始上手!</p> <h3 class="relative group flex items-baseline"> <a id="meta-world-集成" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#meta-world-%E9%9B%86%E6%88%90" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Meta-World 集成 </span> </h3> <p>我们已集成 <a href="https://meta-world.github.io/" rel="nofollow">Meta-World</a>,它是评测机器人操作多任务与泛化能力的一流基准,包含 50+ 种多样化的操作任务。配合我们对 <code>gymnasium ≥ 1.0.0</code> 与 <code>mujoco ≥ 3.0.0</code> 的标准化使用,这一集成为确定性的随机种子与稳健的仿真基础提供了保障。</p> <p>立即使用 <a href="https://huggingface.co/datasets/lerobot/metaworld_mt50">Meta-World 数据集</a> 训练你的策略吧!</p> <h2 class="relative group flex items-baseline"> <a id="代码库:人人可用的强力工具" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E4%BB%A3%E7%A0%81%E5%BA%93%EF%BC%9A%E4%BA%BA%E4%BA%BA%E5%8F%AF%E7%94%A8%E7%9A%84%E5%BC%BA%E5%8A%9B%E5%B7%A5%E5%85%B7" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 代码库:人人可用的强力工具 </span> </h2> <p>我们让机器人控制更加灵活与易用,解锁数据采集与模型训练的新可能。</p> <h3 class="relative group flex items-baseline"> <a id="全新的数据处理-pipeline" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%85%A8%E6%96%B0%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86-pipeline" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 全新的数据处理 Pipeline </span> </h3> <p>让数据从机器人流向模型(再流回去!)并不容易。原始传感器数据、关节位置与语言指令,与人工智能模型期望的输入并不一致。模型需要在正确设备上的规范化、按批次的张量,而你的机器人硬件则需要特定格式的动作命令。</p> <p>我们很高兴地推出 <strong>Processors</strong>:一个模块化的数据处理 Pipeline,可充当通用的“数据翻译器”。你可以把它想象为一条装配线,每个 <code>ProcessorStep</code> 只处理一个明确的工序——例如归一化、文本 Token 化、或将数据移到 GPU。</p> <p>你可以将这些步骤串联起来,构建强大的 Pipeline,精准管理你的数据流。我们还提供了两类开箱即用的 Pipeline,进一步降低使用门槛:</p> <ul> <li><code>PolicyProcessorPipeline</code>:面向模型。专为高性能训练与推理处理按批次的张量。</li> <li><code>RobotProcessorPipeline</code>:面向硬件。以单条数据(如单次观测或动作)为粒度,服务于实时机器人控制。</li> </ul> <pre><code class="language-python"><span class="hljs-comment"># 获取环境状态</span> obs = robot.get_observation() <span class="hljs-comment"># 重命名、打批、归一化、文本分词、移动到设备 ...</span> obs_processed = preprocess(obs) <span class="hljs-comment"># 推理</span> action = model.select_action(obs_processed) <span class="hljs-comment"># 反归一化、移动设备 ...</span> action_processed = postprocess(action) <span class="hljs-comment"># 执行动作</span> robot.send_action(action_processed) </code></pre> <p>这个系统让任何策略与任何机器人都能简单互联,确保你的数据在每一步都处于“刚刚好”的格式。详情可阅读我们的 <a href="https://huggingface.co/docs/lerobot/introduction_processors">Processors 入门文档</a>。</p> <h3 class="relative group flex items-baseline"> <a id="多-gpu-训练更简单" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%A4%9A-gpu-%E8%AE%AD%E7%BB%83%E6%9B%B4%E7%AE%80%E5%8D%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 多 GPU 训练更简单 </span> </h3> <p>大规模机器人策略的训练现在更快了!我们将 <a href="https://github.com/huggingface/accelerate" rel="nofollow">Accelerate</a> 直接整合进训练 Pipeline,只需 <strong>一条命令</strong> 即可在多块 GPU 上无缝扩展你的实验:</p> <pre><code class="language-bash">accelerate launch \ --multi_gpu \ --num_processes=<span class="hljs-variable">$NUM_GPUs</span> \ $(<span class="hljs-built_in">which</span> lerobot-train) \ --dataset.repo_id=<span class="hljs-variable">${HF_USER}</span>/my_dataset \ --policy.repo_id=<span class="hljs-variable">${HF_USER}</span>/my_trained_policy \ --policy.type=<span class="hljs-variable">$POLICY_TYPE</span> \ <span class="hljs-comment"># ... 更多训练配置参数</span> </code></pre> <p>无论是对策略进行微调,还是开展大规模实验,LeRobot 现在都能替你处理分布式训练的全部复杂性。这意味着你可以大幅缩短训练时间:约 2 块 GPU 可减半,约 3 块 GPU 可降至三分之一,更多 GPU 效率更高。</p> <p>查阅 <a href="https://huggingface.co/docs/lerobot/multi_gpu_training">文档</a> 加速你的机器人学习!</p> <h2 class="relative group flex items-baseline"> <a id="策略:释放开放世界泛化能力" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E7%AD%96%E7%95%A5%EF%BC%9A%E9%87%8A%E6%94%BE%E5%BC%80%E6%94%BE%E4%B8%96%E7%95%8C%E6%B3%9B%E5%8C%96%E8%83%BD%E5%8A%9B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 策略:释放开放世界泛化能力 </span> </h2> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot-blog/release-v0.4.0/lerobot-libero-groot2-v040.gif" rel="nofollow"><img src="https://imgproxy.citrusreader.com/2XoiS6MmBQHYZYqjR6KdHIRZineYB-aAjUmcEJFWHJ4/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vbGVyb2JvdC1ibG9nL3JlbGVhc2UtdjAuNC4wL2xlcm9ib3QtbGliZXJvLWdyb290Mi12MDQwLmdpZg" alt="groot-demo" referrerpolicy="no-referrer"></a></p> <h3 class="relative group flex items-baseline"> <a id="pi0-与-pi05" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#pi0-%E4%B8%8E-pi05" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> PI0 与 PI0.5 </span> </h3> <p>在开源机器人领域的一个重要里程碑中,我们将 Physical Intelligence 的 <strong>pi0</strong> 与 <strong>pi0.5</strong> 策略集成进了 LeRobot!这些 VLA(视觉-语言-动作)模型在解决开放世界泛化问题上迈出了重要一步。那么,π0.5 的革命性体现在哪里?</p> <ul> <li><strong>开放世界泛化</strong>:能够适应完全陌生的环境与情境,在物理、语义与环境层面实现跨域泛化。</li> <li><strong>异构数据共训练</strong>:从多模态网页数据、自然语言指令、子任务命令与多环境机器人数据的多样组合中学习。</li> <li><strong>Physical Intelligence 合作</strong>:特别感谢 <a href="https://huggingface.co/physical-intelligence">Physical Intelligence 团队</a> 的开创性工作!</li> </ul> <p>你可以在 Hugging Face Hub 上找到这些模型:<a href="https://huggingface.co/lerobot/pi05_base">pi0.5_base</a>、<a href="https://huggingface.co/lerobot/pi0_base">pi0_base</a> 及它们的 Libero 微调版本。更多细节请参考 <a href="https://www.physicalintelligence.company/blog/pi05" rel="nofollow">Physical Intelligence 的研究博客</a>。</p> <h3 class="relative group flex items-baseline"> <a id="gr00t-n15" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#gr00t-n15" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> GR00T N1.5 </span> </h3> <p>另一项令人振奋的进展是,我们与 NVIDIA 机器人团队携手,将 <strong>GR00T N1.5</strong> 集成进 LeRobot!这是一款面向泛化的开源基础模型,能够进行跨本体的推理与技能迁移。它接收多模态输入(如语言与图像),可在多样环境中执行复杂的操作任务,标志着通用机器人又一大步。GR00T N1.5 为何与众不同?</p> <ul> <li><strong>泛化推理与技能</strong>:作为跨本体的基础模型,GR00T N1.5 擅长泛化推理与操作任务,并提升了语言跟随能力。</li> <li><strong>大规模异构训练</strong>:训练数据覆盖真实人形机器人采集数据、NVIDIA Isaac GR00T Blueprint 生成的合成数据,以及互联网规模的视频数据。</li> <li><strong>与 NVIDIA 合作</strong>:我们很高兴与 <a href="https://huggingface.co/nvidia">NVIDIA 团队</a> 合作,将这一前沿模型带给开源的 LeRobot 社区!</li> </ul> <p>你可以在 Hugging Face Hub 上找到该模型:<a href="https://huggingface.co/nvidia/GR00T-N1.5-3B">GR00T-N1.5-3B</a>。更多信息请查看 <a href="https://research.nvidia.com/labs/gear/gr00t-n1_5/" rel="nofollow">NVIDIA 的研究页面</a> 与 <a href="https://github.com/NVIDIA/Isaac-GR00T" rel="nofollow">官方 GitHub 仓库</a>。</p> <p>这些策略在 <code>lerobot</code> 中的原生集成,让机器人学习更开放、更可复现。立即试用、分享你的训练运行结果,让我们共同推动具身智能的前沿!</p> <h2 class="relative group flex items-baseline"> <a id="机器人:插件系统引领硬件集成新纪元" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%9C%BA%E5%99%A8%E4%BA%BA%EF%BC%9A%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%BC%95%E9%A2%86%E7%A1%AC%E4%BB%B6%E9%9B%86%E6%88%90%E6%96%B0%E7%BA%AA%E5%85%83" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 机器人:插件系统引领硬件集成新纪元 </span> </h2> <p>对硬件爱好者而言的重磅消息!我们发布了全新的插件系统,彻底改造了第三方硬件与 LeRobot 的集成方式。现在,只需一次 <code>pip install</code>,就能连接任意机器人、相机或遥操作设备,无需修改核心库。</p> <h3 class="relative group flex items-baseline"> <a id="核心优势" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%A0%B8%E5%BF%83%E4%BC%98%E5%8A%BF" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 核心优势 </span> </h3> <ul> <li><strong>可扩展性</strong>:在独立的 Python 包中开发并集成自定义硬件。</li> <li><strong>规模化</strong>:支持不断增长的设备生态,而不会“增肥”核心库。</li> <li><strong>社区友好</strong>:降低社区贡献门槛,促进更高效的协作。</li> </ul> <p>想要创建自己的插件?请阅读我们的 <a href="https://huggingface.co/docs/lerobot/integrate_hardware#using-your-own-lerobot-devices-">文档</a>。</p> <pre><code class="language-bash">pip install lerobot_teleoperator_my_awesome_teleop lerobot-teleoperate --teleop.type=my_awesome_teleop </code></pre> <h3 class="relative group flex items-baseline"> <a id="reachy-2-集成" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#reachy-2-%E9%9B%86%E6%88%90" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Reachy 2 集成 </span> </h3> <p>得益于全新插件系统,我们已将 Pollen Robotics 的 <a href="https://www.pollen-robotics.com/reachy/" rel="nofollow">Reachy 2</a> 集成到 LeRobot 中!Reachy 2 同时支持真实机器人控制与仿真,让你可以立即开展遥操作与自主演示实验。</p> <h3 class="relative group flex items-baseline"> <a id="手机集成" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%89%8B%E6%9C%BA%E9%9B%86%E6%88%90" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 手机集成 </span> </h3> <p>得益于强大的新 Pipeline 系统,你现在可以<strong>直接用手机</strong>(iOS/Android)遥操作你的从动机械臂。手机作为遥操作设备,<code>RobotProcessor</code> Pipeline 负责全部数据变换,让你轻松在不同动作空间(如末端执行器空间)驱动机器人。<a href="https://github.com/huggingface/lerobot/tree/main/examples/phone_to_so100" rel="nofollow">查看示例</a>。</p> <h2 class="relative group flex items-baseline"> <a id="hugging-face-机器人学习课程" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#hugging-face-%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E8%AF%BE%E7%A8%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> Hugging Face 机器人学习课程 </span> </h2> <p>我们上线了一门全面、可自学、且完全<strong>开源</strong>的课程,旨在让机器人学习真正“人人可学”!如果你对真实世界中的机器人如何学习感兴趣,这是绝佳的起点。</p> <p>在这门课程中,你将学到:</p> <ul> <li>理解经典机器人学的基础知识。</li> <li>使用生成式模型进行模仿学习(VAE、扩散模型等)。</li> <li>将强化学习应用于真实机器人。</li> <li>探索最新的通用机器人策略,如 PI0 与 SmolVLA。</li> </ul> <p>加入 <a href="https://huggingface.co/robotics-course">Hugging Face Robotics 组织</a> 一起学习吧!</p> <h3 class="relative group flex items-baseline"> <a id="深入讲解:现代机器人学习教程" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E6%B7%B1%E5%85%A5%E8%AE%B2%E8%A7%A3%EF%BC%9A%E7%8E%B0%E4%BB%A3%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 深入讲解:现代机器人学习教程 </span> </h3> <p>我们还发布了一篇<strong>动手实践</strong>的现代机器人学习教程,系统梳理近期的关键进展。该指南从第一性原理重新推导现代技术,并提供可直接运行的示例代码,全面基于 LeRobot 与 Hugging Face。</p> <p>教程托管在一个 <a href="https://huggingface.co/spaces/lerobot/robot-learning-tutorial">Space</a> 中,包含大量基于 LeRobot 的实操示例,所有模型与数据集均在 Hugging Face Hub 上。同时你也可以查看 <a href="https://huggingface.co/papers/2510.12403">我们的论文</a> 以获得更全面的概览。</p> <h2 class="relative group flex items-baseline"> <a id="团队总结" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/lerobot-release-v040#%E5%9B%A2%E9%98%9F%E6%80%BB%E7%BB%93" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 团队总结 </span> </h2> <p>除了以上重大功能,这个版本还包含大量的错误修复、文档改进、依赖更新、更多示例与更好的基础设施,只为让你在使用 LeRobot 时获得更顺滑、更可靠的体验。</p> <p>衷心感谢<strong>每一位社区成员</strong>的宝贵贡献、反馈与支持。我们对开源机器人的未来无比期待,也迫不及待地想与你一起构建下一步!</p> <p>更多精彩,敬请期待 🤗 现在就从 <a href="https://github.com/huggingface/lerobot" rel="nofollow">这里</a> 开始吧! —— LeRobot 团队 ❤️</p>

2025/10/24
阅读更多

用开源模型强化你的 OCR 工作流

<div class="SVELTE_HYDRATER contents" data-target="RepoCodeCopy" data-props="{}"><div></div></div> <div> <a target="_blank" class="btn mb-5 font-sans text-sm no-underline" href="https://github.com/huggingface/blog/blob/main/zh/ocr-open-models.md">在 GitHub 上更新</a></div> <blockquote> <p></p>[!提示] 我们在这篇文章中新增了 <a href="https://huggingface.co/datalab-to/chandra">Chandra</a> 和 <a href="https://huggingface.co/allenai/olmOCR-2-7B-1025">OlmOCR-2</a>,并附上了它们在 OlmOCR 基准上的得分 🫡<p></p> </blockquote> <p><strong>摘要:</strong> 强大的视觉语言模型(Vision-Language Models, VLMs)的崛起,正在彻底改变文档智能(Document AI)的格局。每种模型都有其独特的优势,因此选择合适的模型变得棘手。相比闭源模型,开源权重的模型在成本效率和隐私保护上更具优势。为了帮助你快速上手,我们整理了这份指南。</p> <p>在本指南中,你将了解到:</p> <ul> <li>当前 OCR 模型的整体格局及其能力</li> <li>何时需要微调模型,何时可直接使用</li> <li>为你的场景选择合适模型时应考虑的关键因素</li> <li>如何超越传统 OCR,探索多模态检索与文档问答</li> </ul> <p>读完之后,你将知道如何选择合适的 OCR 模型、开始构建应用,并对文档 AI 有更深入的理解。让我们开始吧!</p> <h2 class="relative group flex items-baseline"> <a id="目录" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E7%9B%AE%E5%BD%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 目录 </span> </h2> <ul> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8%E5%BC%80%E6%BA%90%E6%A8%A1%E5%9E%8B%E6%8F%90%E5%8D%87%E4%BD%A0%E7%9A%84-ocr-%E6%B5%81%E6%B0%B4%E7%BA%BF%E8%83%BD%E5%8A%9B" rel="nofollow">使用开源模型提升你的 OCR 流水线能力</a></p> <ul> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E7%8E%B0%E4%BB%A3-ocr-%E7%AE%80%E4%BB%8B" rel="nofollow">现代 OCR 简介</a></p> <ul> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%83%BD%E5%8A%9B" rel="nofollow">模型能力</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%96%87%E5%AD%97%E8%AF%86%E5%88%AB" rel="nofollow">文字识别</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E5%A4%84%E7%90%86%E6%96%87%E6%A1%A3%E4%B8%AD%E7%9A%84%E5%A4%8D%E6%9D%82%E7%BB%84%E4%BB%B6" rel="nofollow">处理文档中的复杂组件</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E8%BE%93%E5%87%BA%E6%A0%BC%E5%BC%8F" rel="nofollow">输出格式</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%9C%AC%E5%9C%B0%E6%80%A7%E6%84%8F%E8%AF%86-locality-awareness" rel="nofollow">本地性意识(Locality Awareness)</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E6%8F%90%E7%A4%BA%E8%AF%8D%E8%83%BD%E5%8A%9B" rel="nofollow">模型提示词能力</a></li> </ul> </li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E5%89%8D%E6%B2%BF%E5%BC%80%E6%BA%90-ocr-%E6%A8%A1%E5%9E%8B" rel="nofollow">前沿开源 OCR 模型</a></p> <ul> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E5%AF%B9%E6%AF%94" rel="nofollow">模型对比</a></p> </li> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0" rel="nofollow">模型评估</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E8%AF%84%E6%B5%8B%E5%9F%BA%E5%87%86" rel="nofollow">评测基准</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%80%A7%E4%BB%B7%E6%AF%94" rel="nofollow">性价比</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E5%BC%80%E6%BA%90-ocr-%E6%95%B0%E6%8D%AE%E9%9B%86" rel="nofollow">开源 OCR 数据集</a></li> </ul> </li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%BF%90%E8%A1%8C%E5%B7%A5%E5%85%B7" rel="nofollow">模型运行工具</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C" rel="nofollow">本地运行</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E8%BF%9C%E7%A8%8B%E8%BF%90%E8%A1%8C" rel="nofollow">远程运行</a></li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E8%B6%85%E8%B6%8A-ocr-%E7%9A%84%E8%83%BD%E5%8A%9B" rel="nofollow">超越 OCR 的能力</a></p> <ul> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E8%A7%86%E8%A7%89%E6%96%87%E6%A1%A3%E6%A3%80%E7%B4%A2%E5%99%A8" rel="nofollow">视觉文档检索器</a></li> <li><a href="https://huggingface.co/blog/zh/ocr-open-models#%E5%9F%BA%E4%BA%8E%E8%A7%86%E8%A7%89%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%E7%9A%84%E6%96%87%E6%A1%A3%E9%97%AE%E7%AD%94" rel="nofollow">基于视觉语言模型的文档问答</a></li> </ul> </li> <li><p><a href="https://huggingface.co/blog/zh/ocr-open-models#%E6%80%BB%E7%BB%93" rel="nofollow">总结</a></p> </li> </ul> </li> </ul> <h2 class="relative group flex items-baseline"> <a id="现代-ocr-简介" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E7%8E%B0%E4%BB%A3-ocr-%E7%AE%80%E4%BB%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 现代 OCR 简介 </span> </h2> <p>光学字符识别(Optical Character Recognition,简称 OCR)是计算机视觉领域最早、也是持续时间最长的研究方向之一。AI 的许多早期实际应用都集中在“将印刷文字转化为可编辑的数字文本”上。</p> <p>随着<a href="https://huggingface.co/blog/vlms">视觉语言模型(Vision-Language Models, VLMs)</a>的兴起,OCR 的能力迎来了飞跃式提升。如今,许多 OCR 模型都是在现有 VLM 的基础上进行微调得到的。但现代模型的能力已远超传统 OCR —— 你不仅可以识别文字,还能基于内容检索文档,甚至直接进行问答。</p> <p>得益于更强大的视觉理解能力,这些模型能处理低质量扫描件、理解复杂元素(如表格、图表、图片等),并将文本与视觉内容融合,以回答跨文档的开放式问题。</p> <h3 class="relative group flex items-baseline"> <a id="模型能力" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%83%BD%E5%8A%9B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 模型能力 </span> </h3> <h4 class="relative group flex items-baseline"> <a id="文本识别" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%96%87%E6%9C%AC%E8%AF%86%E5%88%AB" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 文本识别 </span> </h4> <p>最新的模型能够将图像中的文字转录为机器可读格式。输入内容可能包括:</p> <ul> <li>手写文字</li> <li>各类文字体系(如拉丁文、阿拉伯文、日文等)</li> <li>数学公式</li> <li>化学方程式</li> <li>图片、版面或页码标签</li> </ul> <p>OCR 模型会将这些内容转换为机器可读的文本,输出格式多种多样,比如 <strong>HTML、Markdown</strong> 等。</p> <h4 class="relative group flex items-baseline"> <a id="处理文档中的复杂组件" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%A4%84%E7%90%86%E6%96%87%E6%A1%A3%E4%B8%AD%E7%9A%84%E5%A4%8D%E6%9D%82%E7%BB%84%E4%BB%B6" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 处理文档中的复杂组件 </span> </h4> <p>除了文字,某些模型还能识别:</p> <ul> <li>图片</li> <li>图表</li> <li>表格</li> </ul> <p>部分模型能识别文档中图片的精确位置,提取其坐标,并在输出中将图片嵌入对应位置。 另一些模型还能为图片生成说明文字(caption),并在适当位置插入。这对于后续将机器可读输出传入 LLM(大型语言模型)尤为有用。</p> <p>例如,<a href="https://huggingface.co/allenai/olmOCR-7B-0825">OlmOCR(AllenAI 出品)</a> 和 <a href="https://huggingface.co/PaddlePaddle/PaddleOCR-VL">PaddleOCR-VL(PaddlePaddle 出品)</a> 就是代表。</p> <p>不同模型使用不同的输出格式,例如 <strong>DocTags</strong>、<strong>HTML</strong>、<strong>Markdown</strong>(后文 <em>输出格式</em> 一节有详细说明)。 模型处理表格与图表的方式通常取决于所采用的输出格式:</p> <ul> <li>有些模型将图表当作图片直接保留;</li> <li>有些模型则会将其转换为可解析的结构化格式,如 Markdown 表格或 JSON。 例如,下图展示了一个柱状图如何被转换成机器可读的形式:</li> </ul> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ocr/chart-rendering.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/vFz4ZEws5aCdHn4Tt1P4CGToI4cNfny5vBW9xD2JVbA/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9vY3IvY2hhcnQtcmVuZGVyaW5nLnBuZw" alt="Chart Rendering" referrerpolicy="no-referrer"></a></p> <p>同样地,表格中的单元格也会被解析为机器可读格式,并保留列名与标题的上下文关系:</p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ocr/table-rendering.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/6X39dkR25hAmnG4HZg3xuZHu5Pk9nNEsDe4AOgHHYGc/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9vY3IvdGFibGUtcmVuZGVyaW5nLnBuZw" alt="Table Rendering" referrerpolicy="no-referrer"></a></p> <h4 class="relative group flex items-baseline"> <a id="输出格式" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E8%BE%93%E5%87%BA%E6%A0%BC%E5%BC%8F" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 输出格式 </span> </h4> <p>不同 OCR 模型采用的输出格式不同,以下是几种主流格式的简介:</p> <ul> <li><p><strong>DocTag:</strong> 一种类似 XML 的文档标记格式,可表达位置信息、文本样式、组件层级等。下图展示了一篇论文如何被解析为 DocTags。该格式由开源的 Docling 模型使用。</p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ocr/doctags_v2.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/6H1QBVMjRc-JZr9wsAH57mmPZRtm7BFfvU8jQyZz6bs/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9vY3IvZG9jdGFnc192Mi5wbmc" alt="DocTags" referrerpolicy="no-referrer"></a></p> </li> <li><p><strong>HTML:</strong> 是最常见的文档解析格式之一,能较好地表达结构与层级信息。</p> </li> <li><p><strong>Markdown:</strong> 人类可读性最强,格式简洁,但表达能力有限(如无法准确表示多列表格)。</p> </li> <li><p><strong>JSON:</strong> 通常用于表示表格或图表中的结构化信息,而非完整文档。</p> </li> </ul> <p>选择合适的模型,取决于你对输出结果的用途:</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th>目标场景</th> <th>推荐格式</th> </tr> </thead><tbody><tr> <td><strong>数字化重建</strong>(重现原始文档版式)</td> <td>使用保留布局的格式,如 DocTags 或 HTML</td> </tr> <tr> <td><strong>LLM 输入或问答场景</strong></td> <td>使用输出 Markdown 和图像说明的模型(更接近自然语言)</td> </tr> <tr> <td><strong>程序化处理</strong>(如数据分析)</td> <td>选择能输出结构化 JSON 的模型</td> </tr> </tbody> </table> </div> <h4 class="relative group flex items-baseline"> <a id="ocr-的位置感知" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#ocr-%E7%9A%84%E4%BD%8D%E7%BD%AE%E6%84%9F%E7%9F%A5" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> OCR 的位置感知 </span> </h4> <p>文档常常结构复杂,比如多栏文本、浮动图片、脚注等。早期的 OCR 模型通常先识别文字,再通过后处理手动推断页面布局,以恢复阅读顺序——这种方式既脆弱又易错。</p> <p>现代 OCR 模型则会在输出中直接包含版面布局信息(称为 <strong>“锚点”或 “grounding”</strong>),如文字的边界框(bounding box)。 这种“锚定”机制能有效保持阅读顺序与语义连贯性,同时减少“幻觉式识别”(即错误生成内容)。</p> <h4 class="relative group flex items-baseline"> <a id="模型提示" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E6%8F%90%E7%A4%BA" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 模型提示 </span> </h4> <p>OCR 模型通常接收图像输入,并可选地接受文字提示(prompt),这取决于模型的架构与预训练方式。</p> <p>部分模型支持<strong>基于提示的任务切换</strong>,例如 <a href="https://huggingface.co/ibm-granite/granite-docling-258M">granite-docling</a> 可以通过不同提示词执行不同任务:</p> <ul> <li>输入 “Convert this page to Docling” → 将整页转换为 DocTags;</li> <li>输入 “Convert this formula to LaTeX” → 将页面中的公式转换为 LaTeX。</li> </ul> <p>而另一些模型则只能处理整页内容,任务由系统提示固定定义。 例如,<a href="https://huggingface.co/collections/allenai/olmocr-67af8630b0062a25bf1b54a1">OlmOCR(AllenAI)</a> 使用一个长系统提示词进行推理。OlmOCR 本质上是基于 Qwen2.5VL 微调的 OCR 模型,虽然它也能处理其他任务,但在 OCR 场景之外性能会明显下降。</p> <h2 class="relative group flex items-baseline"> <a id="前沿开源-ocr-模型" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%89%8D%E6%B2%BF%E5%BC%80%E6%BA%90-ocr-%E6%A8%A1%E5%9E%8B" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 前沿开源 OCR 模型 </span> </h2> <p>过去一年,我们见证了 OCR 模型领域的爆发式创新。由于开源生态的推动,不同团队之间可以相互借鉴、迭代,从而加速了技术进步。一个典型例子是 AllenAI 发布的 <strong>OlmOCR</strong>,它不仅开源了模型本身,还公开了训练所用的数据集,为他人提供了可复现与可扩展的基础。 这个领域正以前所未有的速度发展,但如何选择最合适的模型,仍然是一个不小的挑战。</p> <h3 class="relative group flex items-baseline"> <a id="最新模型对比" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%9C%80%E6%96%B0%E6%A8%A1%E5%9E%8B%E5%AF%B9%E6%AF%94" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 最新模型对比 </span> </h3> <p>为了帮助大家更清晰地了解当前格局,以下是一些当前主流开源 OCR 模型的非完整对比。 这些模型都具备版面理解能力(layout-aware),能解析表格、图表与数学公式。 各模型支持的语言范围可在其 model card 中查看。除 <strong>Chandra</strong>(OpenRAIL 许可)与 <strong>Nanonets</strong>(许可证不明)外,其余均为开源许可。</p> <p>表格中展示的平均得分来自 <strong>Chandra</strong> 与 <strong>OlmOCR</strong> 模型卡中在 <strong>OlmOCR Benchmark</strong>(仅英文)上的测试结果。 此外,许多模型基于 <strong>Qwen2.5-VL</strong> 或 <strong>Qwen3-VL</strong> 微调,因此我们也附上了 Qwen3-VL 作为参考。</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th align="left">模型名称</th> <th align="left">输出格式</th> <th align="left">特性</th> <th align="left">模型大小</th> <th align="left">是否多语言</th> <th align="left">OlmOCR 基准平均得分</th> </tr> </thead><tbody><tr> <td align="left"><a href="https://huggingface.co/collections/nanonets/nanonets-ocr2-68ed207f17ee6c31d226319e">Nanonets-OCR2-3B</a></td> <td align="left">结构化 Markdown(含语义标注、HTML 表格等)</td> <td align="left">图片自动生成说明<br>可提取签名与水印<br>识别复选框、流程图、手写体</td> <td align="left">4B</td> <td align="left">✅ 英语、中文、法语、阿拉伯语等</td> <td align="left">N/A</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/collections/PaddlePaddle/paddleocr-vl-68f0db852483c7af0bc86849">PaddleOCR-VL</a></td> <td align="left">Markdown、JSON、HTML 表格与图表</td> <td align="left">支持手写体与旧文档<br>支持提示词输入<br>可将表格与图表转换为 HTML<br>可直接提取并插入图片</td> <td align="left">0.9B</td> <td align="left">✅ 支持 109 种语言</td> <td align="left">N/A</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/rednote-hilab/dots.ocr">dots.ocr</a></td> <td align="left">Markdown、JSON</td> <td align="left">支持 grounding<br>可提取并插入图片<br>支持手写体</td> <td align="left">3B</td> <td align="left">✅ 多语言(具体未说明)</td> <td align="left">79.1 ± 1.0</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/allenai/olmOCR-2-7B-1025">OlmOCR-2</a></td> <td align="left">Markdown、HTML、LaTeX</td> <td align="left">具备 grounding 能力<br>优化了大规模批处理性能</td> <td align="left">8B</td> <td align="left">❎ 仅英语</td> <td align="left">82.3 ± 1.1</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/ibm-granite/granite-docling-258M">Granite-Docling-258M</a></td> <td align="left">DocTags</td> <td align="left">支持基于提示的任务切换<br>可指定元素位置<br>输出内容丰富</td> <td align="left">258M</td> <td align="left">✅ 英语、日语、阿拉伯语、中文</td> <td align="left">N/A</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/deepseek-ai/DeepSeek-OCR">DeepSeek-OCR</a></td> <td align="left">Markdown、HTML</td> <td align="left">支持通用视觉理解<br>能将图表、表格完整渲染为 HTML<br>识别手写体<br>内存高效,图像文字识别能力强</td> <td align="left">3B</td> <td align="left">✅ 近 100 种语言</td> <td align="left">75.4 ± 1.0</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/datalab-to/chandra">Chandra</a></td> <td align="left">Markdown、HTML、JSON</td> <td align="left">具备 grounding 能力<br>能原样提取并插入图片</td> <td align="left">9B</td> <td align="left">✅ 支持 40+ 种语言</td> <td align="left">83.1 ± 0.9</td> </tr> <tr> <td align="left"><a href="https://huggingface.co/collections/Qwen/qwen3-vl">Qwen3-VL</a></td> <td align="left">任意格式输出(多模态语言模型)</td> <td align="left">识别古文文本<br>支持手写体<br>图片可原样提取插入</td> <td align="left">9B</td> <td align="left">✅ 支持 32 种语言</td> <td align="left">N/A</td> </tr> </tbody> </table> </div> <blockquote> <p><strong>注:</strong> Qwen3-VL 是一款强大的通用视觉语言模型,支持多种文档理解任务,但并未针对 OCR 任务进行特别优化。 其他模型多采用固定提示词进行微调,专为 OCR 任务设计。 因此若使用 Qwen3-VL,建议尝试不同提示词以获得更佳效果。</p> </blockquote> <p>你可以通过这个 <a href="https://prithivmlmods-multimodal-ocr3.hf.space/" rel="nofollow">在线演示</a> 体验部分最新模型并比较输出效果:</p> <iframe src="https://prithivmlmods-multimodal-ocr3.hf.space/" frameborder="0" width="850" height="450" sandbox="allow-scripts" referrerpolicy="same-origin"></iframe> <h3 class="relative group flex items-baseline"> <a id="模型评估" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 模型评估 </span> </h3> <h4 class="relative group flex items-baseline"> <a id="基准测试" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 基准测试 </span> </h4> <p>没有任何一款模型能在所有场景中都是“最优”。 例如:表格应以 Markdown 还是 HTML 呈现?哪些元素需要提取?如何量化文本识别准确度?👀 这些都取决于具体任务。 目前已有多个公开评测集与工具,但仍无法覆盖所有情况。 我们推荐以下常用的评测基准:</p> <ol> <li><p><strong><a href="https://huggingface.co/datasets/opendatalab/OmniDocBench">OmniDocBenchmark</a></strong></p> <ul> <li>这是目前使用最广泛的文档识别基准之一。</li> <li>覆盖文档类型丰富:书籍、杂志、教材等。</li> <li>支持多格式(HTML 与 Markdown)表格评测。</li> <li>使用新型算法评估阅读顺序;公式会在评估前标准化。</li> <li>指标基于“编辑距离”或“树编辑距离”(表格部分)。</li> <li>标注数据部分由 SoTA VLM 或传统 OCR 生成。</li> </ul> </li> <li><p><strong><a href="https://huggingface.co/datasets/allenai/olmOCR-bench">OlmOCR-Bench</a></strong></p> <ul> <li>采用“单元测试式”评估方式。</li> <li>例如:表格评估通过验证单元格间关系完成。</li> <li>数据源为公开 PDF,标注来自多种闭源 VLM。</li> <li>特别适合评估英文 OCR 模型。</li> </ul> </li> <li><p><strong><a href="https://huggingface.co/datasets/wulipc/CC-OCR">CC-OCR (Multilingual)</a></strong></p> <ul> <li>与前两者相比,CC-OCR 的文档质量与多样性较低。</li> <li>但它是<strong>唯一</strong>涵盖英语与中文以外语言的多语言评测集。</li> <li>图片多为低质量拍摄,文本较少。</li> <li>尽管不完美,但目前仍是最佳的多语言评估选项。</li> </ul> </li> </ol> <p>在不同文档类型、语言与任务场景下,模型表现差异明显。 如果你的业务领域不在现有评测集中体现,我们建议收集代表性样本,构建自定义测试集,比较不同模型在你的特定任务上的效果。</p> <h4 class="relative group flex items-baseline"> <a id="成本与效率" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%88%90%E6%9C%AC%E4%B8%8E%E6%95%88%E7%8E%87" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 成本与效率 </span> </h4> <p>大多数 OCR 模型的规模在 <strong>3B~7B 参数</strong>之间,也有一些小型模型(如 PaddleOCR-VL 仅 0.9B)。 成本不仅与模型大小相关,还取决于是否支持高效推理框架。</p> <p>例如:</p> <ul> <li><p><strong>OlmOCR-2</strong> 提供 vLLM 与 SGLang 实现。</p> <ul> <li>若在 H100 GPU($2.69/小时)上运行,推理成本约为 <strong>每百万页 $178</strong>。</li> </ul> </li> <li><p><strong>DeepSeek-OCR</strong> 能在一块 40GB A100 上每天处理 <strong>20 万页以上</strong>。</p> <ul> <li>以此估算,其成本与 OlmOCR 大致相当(视 GPU 供应商而定)。</li> </ul> </li> </ul> <p>若任务对精度要求不高,还可选择 <strong>量化版本(Quantized Models)</strong>,进一步降低成本。 总体而言,开源模型在大规模部署时几乎总比闭源方案更经济。</p> <h4 class="relative group flex items-baseline"> <a id="开源-ocr-数据集" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%BC%80%E6%BA%90-ocr-%E6%95%B0%E6%8D%AE%E9%9B%86" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 开源 OCR 数据集 </span> </h4> <p>尽管近年来开源 OCR 模型大量涌现,但公开的训练与评测数据集仍相对稀缺。 一个例外是 AllenAI 的 <a href="https://huggingface.co/datasets/allenai/olmOCR-mix-0225">olmOCR-mix-0225</a>, 截至目前,该数据集已被用于训练至少 <a href="https://huggingface.co/models?dataset=dataset:allenai/olmOCR-mix-0225">72 个模型</a>(可能更多)。</p> <p>更广泛的数据共享将极大推动开源 OCR 的进步。 以下是几种常见的数据集构建方式:</p> <ul> <li><strong>合成数据生成(Synthetic Data Generation)</strong> 例如:<a href="https://huggingface.co/datasets/Sigurdur/isl_synthetic_ocr">isl_synthetic_ocr</a></li> <li><strong>VLM 自动转录</strong>,再经人工或启发式过滤</li> <li><strong>利用现有 OCR 模型生成新训练数据</strong>,以训练更高效的领域专用模型</li> <li><strong>基于人工校正语料的再利用</strong>,如 <a href="https://huggingface.co/NationalLibraryOfScotland">英国印度医学史数据集</a>, 其中包含大量人工修正的历史文档 OCR</li> </ul> <p>值得注意的是,许多此类数据集已存在但尚未“训练化”(training-ready)。 若能系统化整理并公开,将为开源社区释放巨大潜力。</p> <h2 class="relative group flex items-baseline"> <a id="模型运行工具" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%A8%A1%E5%9E%8B%E8%BF%90%E8%A1%8C%E5%B7%A5%E5%85%B7" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 模型运行工具 </span> </h2> <p>我们收到许多关于“如何开始使用 OCR 模型”的问题,因此这里总结了几种简单的方式—— 包括在本地运行推理,或通过 Hugging Face 进行远程托管。</p> <h3 class="relative group flex items-baseline"> <a id="本地运行" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 本地运行 </span> </h3> <p>目前大多数先进 OCR 模型都提供 <strong>vLLM</strong> 支持,并可通过 <strong>transformers</strong> 库直接加载推理。 你可以在各模型的 Hugging Face 页面找到具体说明。 下面我们以 <strong>vLLM 推理方式</strong>为例演示基本流程。</p> <h4 class="relative group flex items-baseline"> <a id="使用-vllm-启动服务" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8-vllm-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用 vLLM 启动服务 </span> </h4> <pre><code class="language-shell">vllm serve nanonets/Nanonets-OCR2-3B </code></pre> <p>然后,你可以通过 OpenAI SDK 进行调用,例如:</p> <pre><code class="language-py"><span class="hljs-keyword">from</span> openai <span class="hljs-keyword">import</span> OpenAI <span class="hljs-keyword">import</span> base64 client = OpenAI(base_url=<span class="hljs-string">"http://localhost:8000/v1"</span>) model = <span class="hljs-string">"nanonets/Nanonets-OCR2-3B"</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">encode_image</span>(<span class="hljs-params">image_path</span>): <span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(image_path, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> image_file: <span class="hljs-keyword">return</span> base64.b64encode(image_file.read()).decode(<span class="hljs-string">"utf-8"</span>) <span class="hljs-keyword">def</span> <span class="hljs-title function_">infer</span>(<span class="hljs-params">img_base64</span>): response = client.chat.completions.create( model=model, messages=[ { <span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: [ { <span class="hljs-string">"type"</span>: <span class="hljs-string">"image_url"</span>, <span class="hljs-string">"image_url"</span>: {<span class="hljs-string">"url"</span>: <span class="hljs-string">f"data:image/png;base64,<span class="hljs-subst">{img_base64}</span>"</span>}, }, { <span class="hljs-string">"type"</span>: <span class="hljs-string">"text"</span>, <span class="hljs-string">"text"</span>: <span class="hljs-string">"Extract the text from the above document as if you were reading it naturally."</span>, }, ], } ], temperature=<span class="hljs-number">0.0</span>, max_tokens=<span class="hljs-number">15000</span> ) <span class="hljs-keyword">return</span> response.choices[<span class="hljs-number">0</span>].message.content img_base64 = encode_image(your_img_path) <span class="hljs-built_in">print</span>(infer(img_base64)) </code></pre> <h4 class="relative group flex items-baseline"> <a id="使用-transformers-运行推理" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8-transformers-%E8%BF%90%E8%A1%8C%E6%8E%A8%E7%90%86" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用 Transformers 运行推理 </span> </h4> <p>Transformers 库提供了标准化的模型定义与接口,可轻松进行推理或微调。 模型可能有两种加载方式:</p> <ol> <li><strong>官方实现</strong>(在 transformers 内定义)</li> <li><strong>remote code 实现</strong>(由模型作者定义,允许 transformers 自动加载)</li> </ol> <p>以下示例展示了如何用 transformers 调用 <strong>Nanonets OCR 模型</strong>:</p> <pre><code class="language-py"><span class="hljs-comment"># 安装依赖:flash-attn 和 transformers</span> <span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> AutoProcessor, AutoModelForImageTextToText model = AutoModelForImageTextToText.from_pretrained( <span class="hljs-string">"nanonets/Nanonets-OCR2-3B"</span>, torch_dtype=<span class="hljs-string">"auto"</span>, device_map=<span class="hljs-string">"auto"</span>, attn_implementation=<span class="hljs-string">"flash_attention_2"</span> ) model.<span class="hljs-built_in">eval</span>() processor = AutoProcessor.from_pretrained(<span class="hljs-string">"nanonets/Nanonets-OCR2-3B"</span>) <span class="hljs-keyword">def</span> <span class="hljs-title function_">infer</span>(<span class="hljs-params">image_url, model, processor, max_new_tokens=<span class="hljs-number">4096</span></span>): prompt = <span class="hljs-string">"""Extract the text from the above document as if you were reading it naturally. Return the tables in html format. Return the equations in LaTeX representation. If there is an image in the document and image caption is not present, add a small description of the image inside the &lt;img&gt;&lt;/img&gt; tag; otherwise, add the image caption inside &lt;img&gt;&lt;/img&gt;. Watermarks should be wrapped in brackets. Ex: &lt;watermark&gt;OFFICIAL COPY&lt;/watermark&gt;. Page numbers should be wrapped in brackets. Ex: &lt;page_number&gt;14&lt;/page_number&gt; or &lt;page_number&gt;9/22&lt;/page_number&gt;. Prefer using ☐ and ☑ for check boxes."""</span> image = Image.<span class="hljs-built_in">open</span>(image_path) messages = [ {<span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"You are a helpful assistant."</span>}, {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: [ {<span class="hljs-string">"type"</span>: <span class="hljs-string">"image"</span>, <span class="hljs-string">"image"</span>: image_url}, {<span class="hljs-string">"type"</span>: <span class="hljs-string">"text"</span>, <span class="hljs-string">"text"</span>: prompt}, ]}, ] text = processor.apply_chat_template(messages, tokenize=<span class="hljs-literal">False</span>, add_generation_prompt=<span class="hljs-literal">True</span>) inputs = processor(text=[text], images=[image], padding=<span class="hljs-literal">True</span>, return_tensors=<span class="hljs-string">"pt"</span>).to(model.device) output_ids = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=<span class="hljs-literal">False</span>) generated_ids = [output_ids[<span class="hljs-built_in">len</span>(input_ids):] <span class="hljs-keyword">for</span> input_ids, output_ids <span class="hljs-keyword">in</span> <span class="hljs-built_in">zip</span>(inputs.input_ids, output_ids)] output_text = processor.batch_decode(generated_ids, skip_special_tokens=<span class="hljs-literal">True</span>, clean_up_tokenization_spaces=<span class="hljs-literal">True</span>) <span class="hljs-keyword">return</span> output_text[<span class="hljs-number">0</span>] result = infer(image_path, model, processor, max_new_tokens=<span class="hljs-number">15000</span>) <span class="hljs-built_in">print</span>(result) </code></pre> <h4 class="relative group flex items-baseline"> <a id="使用-mlx(适用于-apple-芯片)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8-mlx%EF%BC%88%E9%80%82%E7%94%A8%E4%BA%8E-apple-%E8%8A%AF%E7%89%87%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用 MLX(适用于 Apple 芯片) </span> </h4> <p><strong>MLX</strong> 是苹果推出的机器学习框架,专为 <strong>Apple Silicon (M 系列)</strong> 设计。 在此基础上构建的 <a href="https://github.com/Blaizzy/mlx-vlm" rel="nofollow">MLX-VLM</a> 能轻松运行视觉语言模型。 你可以在 <a href="https://huggingface.co/models?sort=trending&amp;search=ocr">Hugging Face</a> 搜索所有支持 MLX 的 OCR 模型(包括量化版本)。</p> <p>安装 MLX-VLM:</p> <pre><code class="language-bash">pip install -U mlx-vlm </code></pre> <p>示例运行:</p> <pre><code class="language-bash">wget https://huggingface.co/datasets/merve/vlm_test_images/resolve/main/throughput_smolvlm.png python -m mlx_vlm.generate \ --model ibm-granite/granite-docling-258M-mlx \ --max-tokens 4096 \ --temperature 0.0 \ --prompt <span class="hljs-string">"Convert this chart to JSON."</span> \ --image throughput_smolvlm.png </code></pre> <h3 class="relative group flex items-baseline"> <a id="远程运行" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E8%BF%9C%E7%A8%8B%E8%BF%90%E8%A1%8C" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 远程运行 </span> </h3> <h4 class="relative group flex items-baseline"> <a id="使用-inference-endpoints-部署模型(托管推理服务)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8-inference-endpoints-%E9%83%A8%E7%BD%B2%E6%A8%A1%E5%9E%8B%EF%BC%88%E6%89%98%E7%AE%A1%E6%8E%A8%E7%90%86%E6%9C%8D%E5%8A%A1%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用 Inference Endpoints 部署模型(托管推理服务) </span> </h4> <p>你可以通过 <strong>Hugging Face Inference Endpoints</strong> 在托管环境中部署兼容 vLLM 或 SGLang 的 OCR 模型。 该服务提供 GPU 加速、自动伸缩、监控与安全托管,无需自行维护基础设施。</p> <p>部署步骤如下:</p> <ol> <li><p>进入模型仓库 <a href="https://huggingface.co/nanonets/Nanonets-OCR2-3B"><code>nanonets/Nanonets-OCR2-3B</code></a></p> </li> <li><p>点击页面上的 <strong>“Deploy”</strong> 按钮,选择 <strong>“HF Inference Endpoints”</strong></p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ocr/IE.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/68CHUsfyxE3ujH3EVhQYUhFLQDCuJCBIDsXbPXaq294/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9vY3IvSUUucG5n" alt="Inference Endpoints" referrerpolicy="no-referrer"></a></p> </li> <li><p>在弹出的窗口中配置部署参数(GPU 类型、实例数量等)</p> <p><a href="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ocr/IE2.png" rel="nofollow"><img src="https://imgproxy.citrusreader.com/r9aGfGyrRS8-_fdTt4yc8jVhtH1J70ncbp-237yTAvI/raw:1/aHR0cHM6Ly9odWdnaW5nZmFjZS5jby9kYXRhc2V0cy9odWdnaW5nZmFjZS9kb2N1bWVudGF0aW9uLWltYWdlcy9yZXNvbHZlL21haW4vYmxvZy9vY3IvSUUyLnBuZw" alt="Inference Endpoints" referrerpolicy="no-referrer"></a></p> </li> <li><p>部署完成后,你可以直接通过上文示例中的 OpenAI 客户端脚本调用该 Endpoint。</p> </li> </ol> <p>更多信息可参阅官方文档: 👉 <a href="https://huggingface.co/docs/inference-endpoints/engines/vllm">Inference Endpoints (vLLM)</a></p> <h4 class="relative group flex items-baseline"> <a id="使用-hugging-face-jobs-进行批量推理" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E4%BD%BF%E7%94%A8-hugging-face-jobs-%E8%BF%9B%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8E%A8%E7%90%86" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 使用 Hugging Face Jobs 进行批量推理 </span> </h4> <p>对于 OCR 场景,往往需要<strong>批量处理成千上万张图像</strong>。 这类任务可通过 <strong>vLLM 的离线推理模式</strong> 实现高效并行。</p> <p>为了简化流程,我们创建了 <a href="https://huggingface.co/datasets/uv-scripts/ocr">uv-scripts/ocr</a>, 它是一组适配 Hugging Face Jobs 的可直接运行脚本,能实现:</p> <ul> <li>对数据集列中的所有图片进行批量 OCR</li> <li>将 OCR 结果以 Markdown 形式新增为新列</li> <li>自动将带结果的数据集回传到 Hub</li> </ul> <p>例如,处理 100 张图片的命令如下:</p> <pre><code class="language-bash">hf <span class="hljs-built_in">jobs</span> uv run --flavor l4x1 \ https://huggingface.co/datasets/uv-scripts/ocr/raw/main/nanonets-ocr.py \ your-input-dataset your-output-dataset \ --max-samples 100 </code></pre> <p>这些脚本会自动处理所有 vLLM 配置与批次推理逻辑, 让批量 OCR 变得无需 GPU 或复杂部署。</p> <h2 class="relative group flex items-baseline"> <a id="超越-ocr" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E8%B6%85%E8%B6%8A-ocr" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 超越 OCR </span> </h2> <p>如果你对文档智能(Document AI)感兴趣,不仅仅局限于文字识别(OCR),以下是我们的一些推荐方向。</p> <h3 class="relative group flex items-baseline"> <a id="视觉文档检索" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E8%A7%86%E8%A7%89%E6%96%87%E6%A1%A3%E6%A3%80%E7%B4%A2" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 视觉文档检索 </span> </h3> <p><strong>视觉文档检索(Visual Document Retrieval)</strong> 指的是: 当你输入一条文本查询时,系统能够从大量 PDF 文档中直接检索出最相关的前 <em>k</em> 篇。</p> <p>与传统文本检索模型不同,视觉文档检索器直接在“文档图像”层面进行搜索。 除了独立使用外,你还可以将它与视觉语言模型结合,构建 <strong>多模态 RAG(Retrieval-Augmented Generation)</strong> 管线。 相关示例可参考:<a href="https://huggingface.co/merve/smol-vision/blob/main/ColPali_%2B_Qwen2_VL.ipynb">ColPali + Qwen2_VL 多模态 RAG 教程</a>。</p> <p>你可以在 <a href="https://huggingface.co/models?pipeline_tag=visual-document-retrieval&amp;sort=trending">Hugging Face Hub</a> 找到所有可用的视觉文档检索模型。</p> <p>目前主流的视觉检索器分为两类:</p> <div class="max-w-full overflow-auto"> <table> <thead><tr> <th>类型</th> <th>特点</th> <th>适用场景</th> </tr> </thead><tbody><tr> <td><strong>单向量模型(Single-vector Models)</strong></td> <td>内存效率高、速度快,但性能略弱</td> <td>轻量化部署、大规模索引</td> </tr> <tr> <td><strong>多向量模型(Multi-vector Models)</strong></td> <td>表征能力强、检索精度高,但占用显存更大</td> <td>高精度检索、知识密集任务</td> </tr> </tbody> </table> </div> <p>大多数此类模型都支持 <strong>vLLM</strong> 和 <strong>transformers</strong>,因此你可以很方便地用它们进行向量索引,然后结合向量数据库(vector DB)执行高效搜索。</p> <h3 class="relative group flex items-baseline"> <a id="基于视觉语言模型的文档问答(document-question-answering)" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%9F%BA%E4%BA%8E%E8%A7%86%E8%A7%89%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%E7%9A%84%E6%96%87%E6%A1%A3%E9%97%AE%E7%AD%94%EF%BC%88document-question-answering%EF%BC%89" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 基于视觉语言模型的文档问答(Document Question Answering) </span> </h3> <p>如果你的任务目标是<strong>基于文档回答问题</strong>(而不是仅仅提取文字), 你可以直接使用经过文档任务训练的<strong>视觉语言模型(VLM)</strong>。</p> <p>许多用户习惯于:</p> <ol> <li>先将文档转换成纯文本;</li> <li>再把文本传入 LLM 进行问答。</li> </ol> <p>这种方式虽然可行,但存在明显缺陷:</p> <ul> <li>一旦文档布局复杂(如多栏结构、图表、图片说明等),转换后的文本就可能丢失关键信息;</li> <li>图表被转为 HTML、图片说明生成错误时,LLM 就会误判或忽略内容。</li> </ul> <p>因此,更好的做法是: 直接将<strong>原始文档图像 + 用户问题</strong> 一起输入支持多模态理解的模型, 例如 <a href="https://huggingface.co/collections/Qwen/qwen3-vl-68d2a7c1b8a8afce4ebd2dbe">Qwen3-VL</a>。 这样模型就能同时利用视觉与文本信息,不会错过任何上下文细节。</p> <h2 class="relative group flex items-baseline"> <a id="总结" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E6%80%BB%E7%BB%93" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 总结 </span> </h2> <p>在这篇文章中,我们为你概览了现代 OCR 技术的核心要点,包括:</p> <ul> <li>如何选择合适的 OCR 模型</li> <li>当前最前沿的开源模型及其能力</li> <li>在本地或云端运行模型的工具</li> <li>以及如何在 OCR 之上构建更复杂的文档智能应用</li> </ul> <p>如果你希望进一步深入了解 OCR 与视觉语言模型(VLM), 以下是我们推荐的延伸阅读与教程资源 👇</p> <h3 class="relative group flex items-baseline"> <a id="延伸阅读与资源" class="block pr-1.5 text-lg md:absolute md:p-1.5 md:opacity-0 md:group-hover:opacity-100 md:right-full" href="https://huggingface.co/blog/zh/ocr-open-models#%E5%BB%B6%E4%BC%B8%E9%98%85%E8%AF%BB%E4%B8%8E%E8%B5%84%E6%BA%90" rel="nofollow"> <span class="header-link"><svg class="text-gray-500 hover:text-black dark:hover:text-gray-200 w-4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg></span> </a> <span> 延伸阅读与资源 </span> </h3> <ul> <li><p>📘 <a href="https://huggingface.co/blog/vlms">Vision Language Models Explained(视觉语言模型详解)</a> —— 深入理解 VLM 的工作原理与发展历程。</p> </li> <li><p>🧠 <a href="https://huggingface.co/blog/vlms-2025">Vision Language Models 2025 Update(2025 年视觉语言模型更新)</a> —— 最新 VLM 技术进展总结。</p> </li> <li><p>🔍 <a href="https://huggingface.co/blog/baidu/ppocrv5">PP-OCR-v5 技术博客</a> —— 来自百度的高性能 OCR 系统优化介绍。</p> </li> <li><p>🧩 <a href="https://huggingface.co/merve/smol-vision/blob/main/Grounded_Fine_tuning.ipynb">教程:微调 Kosmos2.5 进行 Grounded OCR</a> —— 实践指南,教你如何让模型具备“锚定式”识别能力。</p> </li> <li><p>📄 <a href="https://huggingface.co/merve/smol-vision/blob/main/Fine_tune_Florence_2.ipynb">教程:在 DocVQA 数据集上微调 Florence-2</a> —— 基于视觉问答任务的微调实例。</p> </li> <li><p>📱 <a href="https://huggingface.co/blog/dots-ocr-ne">在设备端实现 SOTA OCR(Core ML + dots.ocr)</a> —— 展示如何在移动端高效部署 OCR 模型。</p> </li> </ul> <p><strong>总结一句话:</strong> 开源视觉语言模型正在重新定义 OCR 的边界。 从纯文本识别到多模态理解、从图像到语义、从离线推理到大规模部署—— 如今的开源生态为每一个开发者和研究者提供了前所未有的自由度与创新空间。</p> <p>无论你是在构建下一代文档智能系统,还是仅想更高效地解析 PDF, 希望这篇指南能帮助你找到最合适的起点 🚀</p>

2025/10/21
阅读更多

推荐订阅

| 精品推荐 | 技术干货 | 职场成长 | 社区动态 | 组件物料 | 行业动态 | | --------- | -------- | -------- | --------- | -------- | -------- | | recommend | quality | growth | community | material | industry |

::: tip 订阅 [管理与运维](https://tidb.net/blog/c/management-and-operation),其源网址为 `https://tidb.net/blog/c/management-and-operation`,请参考该 URL 指定部分构成参数,此时路由为 [`/tidb/blog/c/management-and-operation`](https://rsshub.app/tidb/blog/c/management-and-operation)。 ::: | 分类 | ID | | -------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [全部文章](https://tidb.net/blog) | [latest](https://rsshub.app/tidb/blog) | | [管理与运维](https://tidb.net/blog/c/management-and-operation) | [management-and-operation](https://rsshub.app/tidb/blog/c/management-and-operation) | | [实践案例](https://tidb.net/blog/c/practical-case) | [practical-case](https://rsshub.app/tidb/blog/c/practical-case) | | [架构选型](https://tidb.net/blog/c/architecture-selection) | [architecture-selection](https://rsshub.app/tidb/blog/c/architecture-selection) | | [原理解读](https://tidb.net/blog/c/principle-interpretation) | [principle-interpretation](https://rsshub.app/tidb/blog/c/principle-interpretation) | | [应用开发](https://tidb.net/blog/c/application-development) | [application-development](https://rsshub.app/tidb/blog/c/application-development) | | [社区动态](https://tidb.net/blog/c/community-feeds) | [community-feeds](https://rsshub.app/tidb/blog/c/community-feeds) |