<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Machine Learning on Hypho - AI Agent 技术博客</title><link>https://blog.hypho.cn/tags/machine-learning/</link><description>Recent content in Machine Learning on Hypho - AI Agent 技术博客</description><image><title>Hypho - AI Agent 技术博客</title><url>https://blog.hypho.cn/papermod-cover.png</url><link>https://blog.hypho.cn/papermod-cover.png</link></image><generator>Hugo -- 0.148.2</generator><language>zh-cn</language><lastBuildDate>Fri, 01 May 2026 10:03:51 +0800</lastBuildDate><atom:link href="https://blog.hypho.cn/tags/machine-learning/index.xml" rel="self" type="application/rss+xml"/><item><title>PyTorch Lightning 供应链攻击复盘：AI 训练依赖为什么不能只靠 pip install</title><link>https://blog.hypho.cn/posts/pytorch-lightning-supply-chain-security/</link><pubDate>Fri, 01 May 2026 10:03:51 +0800</pubDate><guid>https://blog.hypho.cn/posts/pytorch-lightning-supply-chain-security/</guid><description>PyTorch Lightning 的 lightning 包被曝出现供应链攻击，恶意版本可在导入时窃取凭证、云端密钥和 GitHub token。本文从 AI 训练依赖、PyPI 发布链路、锁文件、哈希校验、CI 隔离和应急轮换角度，分析机器学习团队如何把 Python 依赖安全做成工程流程，而不是事后补救。</description><content:encoded><![CDATA[<p>如果你在训练脚本里写过 <code>pip install lightning</code>，这次事件就不只是安全圈的新闻。它提醒的是一个更难听的事实：很多 AI 团队的“训练基础设施”，其实建立在一条几乎没人认真审计的依赖链上。模型代码、数据集、实验追踪、云端凭证都在同一个环境里跑，任何一个热门 Python 包被污染，攻击面都会比普通 Web 服务更肥。</p>
<p>HN 上这条 <a href="https://news.ycombinator.com/item?id=47964617">Semgrep 披露</a> 很快冲到前排，原因也不复杂：被点名的是 Lightning 生态里的 <code>lightning</code> 包。Semgrep 的研究文章称，PyPI 上 <code>lightning</code> 2.6.2 和 2.6.3 在 2026 年 4 月 30 日被发布为恶意版本，导入时会执行隐藏在 <code>_runtime</code> 目录里的混淆 JavaScript payload，尝试窃取凭证、认证 token、环境变量和云端 secret，并带有 Shai-Hulud 风格的仓库投毒行为。原文细节见 <a href="https://semgrep.dev/blog/2026/malicious-dependency-in-pytorch-lightning-used-for-ai-training/">Semgrep: Shai-Hulud Themed Malware Found in the PyTorch Lightning AI Training Library</a>。</p>
<p>我不想把这篇写成“某某包又中招了”的快讯。快讯今天看完，明天就忘。更值得拆的是：为什么 AI/ML 工程里的同类事故破坏力特别大？以及，一个现实团队到底应该改哪几件事。</p>
<p>先把边界说清楚。PyTorch Lightning 本身是一个真实、活跃且规模很大的开源项目，GitHub 仓库 <a href="https://github.com/Lightning-AI/pytorch-lightning">Lightning-AI/pytorch-lightning</a> 有 3 万级 stars，近期仍有提交；PyPI 上当前可见的 <a href="https://pypi.org/project/lightning/">lightning 项目页</a> 也显示稳定版本和维护者信息。这类事件的重点通常不是“项目没价值”，而是“发布链路或账号链路被污染后，价值越大的包越适合被当成入口”。</p>
<p>说白了，热门依赖就是最好的投递渠道。</p>
<p>AI 训练环境为什么更危险？第一，它天然带 secret。为了拉数据、写 S3、连实验平台、访问模型 API、推送镜像，训练机里经常有 <code>AWS_ACCESS_KEY_ID</code>、Hugging Face token、Weights &amp; Biases key、GitHub token、数据库只读账号，甚至还有企业内部对象存储凭证。普通后端服务至少还会被平台团队逼着走 secret manager；很多研究环境则是 <code>.env</code>、notebook、shell history 混着来。</p>
<p>第二，训练脚本的“导入即执行”风险被低估了。Python 包安装阶段能执行构建脚本，导入阶段也能跑任意初始化逻辑。Semgrep 披露里特别刺眼的一点是：恶意代码不需要你调用某个奇怪 API，只要环境里安装了受影响版本，常规导入路径就可能触发。人话翻译：这不是“你点了钓鱼链接才中招”，而是“你正常跑训练就可能把钥匙交出去”。</p>
<p>第三，AI 项目的依赖树太宽。一个看起来简单的 fine-tuning 项目，下面可能挂着 PyTorch、Lightning、Transformers、tokenizers、datasets、加速库、日志库、可视化库、云 SDK。很多团队用 <code>pip install -U</code> 或者裸 <code>requirements.txt</code> 管开发环境，版本边界非常松。今天 CI 过了，不代表明天新机器重建环境拿到的是同一批 wheel。</p>
<p>这也是我一直不太喜欢把“可复现实验”只理解成随机种子和数据切分的原因。依赖不可复现，实验就不可复现；依赖不可验证，训练环境也谈不上安全。</p>
<p>工程上第一步不是买更贵的扫描器，而是停止裸装生产训练依赖。至少做到三件小事：锁版本、锁哈希、锁来源。</p>
<p>锁版本很好理解：不要写 <code>lightning&gt;=2.0</code> 这种在生产训练镜像里自动漂移的约束。用 <code>pip-tools</code>、Poetry、uv 或内部构建系统生成 lockfile，把直接依赖和传递依赖都固定下来。更进一步，pip 支持 <code>--require-hashes</code>，可以要求每个包文件匹配预期 hash。这个方案麻烦，尤其在依赖多、平台多的时候会增加维护成本，但它解决的是最核心的问题：同一个版本号对应的文件，不能悄悄换。</p>
<p>PyPI 自己也在往这个方向补基础设施。官方的 <a href="https://docs.pypi.org/attestations/">PyPI digital attestations 文档</a> 说明，PEP 740 相关机制允许发布者或第三方对包分发文件做数字证明，把具体 wheel/sdist 的内容摘要与发布身份绑定。别误会，attestation 不是银弹；它不能保证代码“没有恶意”，只能让你更清楚“这个文件是谁、通过什么流程发布的”。但在供应链排障里，这已经比肉眼看版本号强很多。</p>
<p>第二步是把训练环境和凭证环境拆开。最糟糕的模式是：CI 拉代码、安装依赖、跑测试、构建镜像、访问云资源，全在一个长寿命 token 下完成。更好的做法是分层：依赖解析和镜像构建发生在无生产 secret 的环境；真正需要访问数据的训练任务只拿最小权限、短期凭证；notebook 和交互式实验环境不要默认继承发布 token。</p>
<p>这听起来像安全八股，但对 AI 团队很实际。因为一旦训练环境泄漏，攻击者拿到的往往不是一台机器，而是一整套数据入口、模型制品和内部代码仓库入口。此前我写 <a href="https://blog.hypho.cn/posts/agent-vault-open-source-credential-proxy/">Agent Vault：用代理模式堵住 AI Agent 的凭证泄露风险</a> 时也提过类似思路：不要把长期凭证直接塞进会执行不可信上下文的进程里。训练脚本不是 Agent，但风险结构非常像——都是“强能力进程 + 大量外部输入 + 容易携带 secret”。</p>
<p>第三步是给 CI 增加“依赖变更审查”这个关卡。很多团队代码 review 很严格，依赖 review 却很随意：<code>requirements.txt</code> 多了几十行，没人看；lockfile 变了几千行，直接点 approve。我的建议是把依赖升级当成小型变更发布：自动标出新增包、维护者变化、下载源变化、是否启用 Trusted Publishing、是否有 yanked/replaced 记录；高风险包升级单独跑沙箱测试，不要和业务代码混在一个 PR 里。</p>
<p>这里有个反直觉点：安全扫描只能发现“已知坏东西”，不能替你判断“这个升级是否应该发生”。比如一个热门 ML 包突然多了 postinstall 行为、突然引入 Node 执行链、突然换了上传方式，这些都未必立刻命中 CVE，却非常值得人工看一眼。</p>
<p>第四步是准备真正能用的应急动作。不是写在 Confluence 里没人看的事故流程，而是可以直接复制执行的那种：冻结依赖源；禁用受影响版本；轮换训练环境里出现过的 cloud key、GitHub token、模型平台 token；清理 CI cache 和 notebook 持久卷；检查近期由自动化账号推送的异常仓库、异常 release、异常 workflow；把镜像重新从干净 lockfile 构建一遍。</p>
<p>如果你用的是 GitHub Actions 或类似 CI，还要特别留意仓库写权限 token。Semgrep 文中提到的仓库投毒行为，真正可怕的不是创建一个奇怪名字的公开仓库，而是攻击者可能利用自动化 token 横向移动。对开源项目这会污染用户信任；对企业内部项目，这可能变成供应链二次传播。</p>
<p>那是不是以后别用 PyPI、别用 Lightning、所有东西都 vendor 进仓库？我觉得这不是现实答案。AI 工程的效率高度依赖开源生态，完全自建会把团队拖死。更合理的判断是：高频实验环境可以保持灵活，但生产训练、评测流水线、模型发布流水线必须像后端服务一样管理依赖。研究阶段追新没问题，交付阶段不能追新。</p>
<p>这里可以借用我在 <a href="https://blog.hypho.cn/posts/local-llm-ollama-llama-cpp/">本地 LLM 推理引擎之争</a> 里反复强调的一个原则：越靠近生产边界，越要减少隐式行为。推理引擎如此，训练依赖也是如此。你不能一边要求模型产物可审计，一边允许构建环境每天从互联网随机拿一组新包。</p>
<p>最后给一个我认为比较务实的最小清单：</p>
<ul>
<li>生产训练镜像禁止裸 <code>pip install -U</code>，必须从 lockfile 构建。</li>
<li>对关键依赖启用 hash 校验或内部包镜像，至少保证重建环境拿到同一份文件。</li>
<li>CI 构建阶段不注入生产 secret；训练运行阶段使用短期、最小权限凭证。</li>
<li>依赖升级 PR 单独审查，新增传递依赖和发布元数据变化要可见。</li>
<li>对 PyPI、GitHub、云账号 token 建立轮换剧本，事故发生时先轮换再争论。</li>
<li>对 notebook、实验机、共享 GPU 服务器做凭证清点，别让历史 <code>.env</code> 变成攻击者的奖池。</li>
</ul>
<p>这次 Lightning 事件未必是最后一次，也大概率不会是最严重的一次。AI 基础设施正在把越来越多高价值资产放进 Python 运行时：数据、模型、私有代码、云资源、评测结果。攻击者不需要理解你的模型结构，只要理解你的安装流程。</p>
<p>有点讽刺，但也很真实：很多团队花几周调一个 1% 的指标提升，却不愿花一天把依赖安装固定下来。等供应链攻击真的打进训练环境，再补这一天就太晚了。</p>
]]></content:encoded></item><item><title>TRELLIS.2 移植到 Mac：没有 NVIDIA 也能跑图片转 3D 模型</title><link>https://blog.hypho.cn/posts/trellis2-apple-silicon-image-to-3d/</link><pubDate>Mon, 20 Apr 2026 10:13:50 +0800</pubDate><guid>https://blog.hypho.cn/posts/trellis2-apple-silicon-image-to-3d/</guid><description>微软 TRELLIS.2 是 CVPR 2025 Spotlight 的 SOTA 图片转 3D 技术，官方只有 CUDA 版本。近日有人将其完整移植到 Apple Silicon，M4 Pro 上 3.5 分钟生成 40 万顶点网格，且全程无需 NVIDIA GPU。本文解析移植思路、关键技术细节，以及为什么 Apple Silicon 的统一内存架构在这类任务上比离散 GPU 更合适。</description><content:encoded><![CDATA[<p>如果你只有一台 Mac 电脑，想从单张图片生成 3D 模型——直到今天，这基本上是个伪需求。市面上最好的开源图片转 3D 技术，几乎全部围绕 NVIDIA CUDA 构建，买不到合适的硬件就等于玩不了。</p>
<p>这个局面正在被打破。</p>
<p>TRELLIS.2 是微软 2025 年发表在 CVPR 的论文提出的图片转 3D 方法，在 GitHub 上有 1.2 万星，官方仓库清一色 CUDA 代码。近日有个开发者把它完整移植到了 Apple Silicon，M4 Pro 上 3.5 分钟就能生成一个 40 万顶点的网格模型，全程跑在苹果自研芯片上，不需要半块 NVIDIA 显卡。</p>
<h2 id="移植的核心思路替换掉-cuda-依赖">移植的核心思路：替换掉 CUDA 依赖</h2>
<p>TRELLIS.2 依赖好几个 CUDA 专用的库，官方版本开箱即用但根本不支持 Metal。这不是简单的编译选项问题，而是代码里大量硬编码了 <code>.cuda()</code> 调用和 CUDA 核函数。</p>
<p>移植的思路很直接：<strong>找到每一个 CUDA 依赖，用 PyTorch 原生功能或纯 Python 实现替换</strong>。</p>
<p>主要替换关系如下：</p>
<table>
  <thead>
      <tr>
          <th>原始（CUDA）</th>
          <th>移植版本</th>
          <th>用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>flex_gemm</code></td>
          <td><code>backends/conv_none.py</code></td>
          <td>子流形稀疏 3D 卷积，通过 gather-scatter 实现</td>
      </tr>
      <tr>
          <td><code>o_voxel._C</code> hashmap</td>
          <td><code>backends/mesh_extract.py</code></td>
          <td>从双体素网格提取网格面</td>
      </tr>
      <tr>
          <td><code>flash_attn</code></td>
          <td>PyTorch SDPA</td>
          <td>稀疏变换器的注意力机制</td>
      </tr>
      <tr>
          <td><code>cumesh</code></td>
          <td>Stub（跳过）</td>
          <td>网格孔填充与简化</td>
      </tr>
      <tr>
          <td><code>nvdiffrast</code></td>
          <td>Stub（跳过）</td>
          <td>可微分光栅化（仅影响纹理导出）</td>
      </tr>
  </tbody>
</table>
<p>稀疏 3D 卷积的替换是个技术亮点。原始 <code>flex_gemm</code> 做的是子流形稀疏卷积——3D 生成任务中只有物体表面有数据，不需要对整个空间做卷积。移植版本用 Python 构建空间哈希表，对每个活跃体素收集邻域特征，通过矩阵乘法应用权重，再把结果 scatter 回去。neighbor maps 做了缓存避免重复计算。</p>
<p>Mesh 提取部分也很有意思。双体素网格到网格面的转换原来用的是 CUDA hashmap，移植版本用 Python 字典重写了 <code>flexibe_dual_grid_to_mesh</code> 函数，逻辑完全对应，只是从 GPU 并行换成了 Python 循环。</p>
<p>整个移植不需要任何 fork——直接 clone 后跑 <code>setup.sh</code>，脚本会自动克隆原始 TRELLIS.2 仓库并应用 patch。</p>
<h2 id="apple-silicon-统一内存被忽视的硬件优势">Apple Silicon 统一内存：被忽视的硬件优势</h2>
<p>这个移植能跑的前提，是 Apple Silicon 的统一内存架构（Unified Memory Architecture）。</p>
<p>在离散 GPU（NVIDIA/AMD）上，CPU 和 GPU 各自有独立显存，数据跨 PCIe 总线传输。把数据从 CPU 内存拷贝到 GPU 显存是不可避免的开销，对于大模型来说这个拷贝时间相当可观。</p>
<p>Apple Silicon 的 CPU 和 GPU 共享同一块物理内存，没有 PCIe 总线的概念。<strong>同一个指针，CPU 能读，GPU 也能读，不需要任何拷贝</strong>。这就是为什么苹果官方一直在推 MLX 机器学习框架，而 MLX 的核心设计思路就是最大化利用统一内存减少数据搬运。</p>
<p>TRELLIS.2 生成的是稀疏 3D 表示，中间激活值在 M4 Pro 上直接复用统一内存，不需要反复搬运。这一点在离散 GPU 上反而是劣势——PCIe 带宽远低于显存带宽，频繁的小数据搬运会让稀疏操作的 overhead 更大。</p>
<h2 id="实测效果够用但有取舍">实测效果：够用，但有取舍</h2>
<p>根据 README 的数据，M4 Pro（24GB 统一内存）上：</p>
<ul>
<li>单张图片生成 400K+ 顶点的 OBJ/GLB 模型，约 3.5 分钟</li>
<li>支持三种 pipeline 分辨率：512、1024、1024 级联</li>
<li>首次运行需要从 HuggingFace 下载约 15GB 模型权重</li>
</ul>
<p>主要限制：</p>
<ul>
<li>需要 24GB+ 统一内存（M4 Pro 或更新）</li>
<li>官方 CUDA 版本可能有更好的网格质量</li>
<li><code>nvdiffrast</code> 的跳过意味着纹理导出功能暂不可用</li>
</ul>
<p>但生成时间和质量对于大多数应用场景已经相当可用——3.5 分钟出一个可编辑的 3D 模型，比云端 API 便宜多了，而且完全本地运行，数据不离开机器。</p>
<h2 id="为什么这件事值得关注">为什么这件事值得关注</h2>
<p>过去一年开源图片转 3D 的进展很快，但生态几乎被 NVIDIA 垄断。TRELLIS.2 的 Apple Silicon 移植不是简单的移植工作——它意味着：</p>
<ol>
<li><strong>苹果生态的 AI 应用开发门槛降低了</strong>。以前想跑这类模型必须买台带 NVIDIA 显卡的机器，现在一台 M4 MacBook Pro 就行</li>
<li><strong>本地推理的边界在扩展</strong>。22B 参数级别的模型用统一内存做推理已经开始可行，这个方向会越来越宽</li>
<li><strong>PyTorch 的 MPS 后端在成熟</strong>。Sparse convolution、SDPA 这些操作以前在 MPS 上支持很差，现在已经能完整实现一个 SOTA 论文的核心算法</li>
</ol>
<p>如果你在 Mac 上做 3D 内容创作、游戏开发或 AR/VR 应用，这个工具链值得放进你的技术栈。</p>
<p><strong>项目地址：</strong></p>
<ul>
<li>Apple Silicon 移植版：<a href="https://github.com/shivampkumar/trellis-mac">github.com/shivampkumar/trellis-mac</a></li>
<li>微软官方原始仓库：<a href="https://github.com/microsoft/TRELLIS">github.com/microsoft/TRELLIS</a>（12k stars，CVPR 2025 Spotlight）</li>
</ul>
]]></content:encoded></item><item><title>GuppyLM: 用一个 Colab 笔记本，在 5 分钟内训练出你自己的 LLM</title><link>https://blog.hypho.cn/posts/guppylm-5-minutes-llm-from-scratch/</link><pubDate>Sun, 12 Apr 2026 12:12:44 +0800</pubDate><guid>https://blog.hypho.cn/posts/guppylm-5-minutes-llm-from-scratch/</guid><description>一个 9M 参数的小模型，如何让大模型不再看起来像黑箱？GuppyLM 通过最简单的 vanilla transformer 架构，展示了从零训练 LLM 的完整流程。</description><content:encoded><![CDATA[<p>昨天在 HN 上看到一个很有想法的项目：作者在 5 分钟内，用一个 Colab 笔记本，从零训练出了一个 9M 参数的语言模型 GuppyLM。</p>
<p>不是跑 demo，不是微调，是<strong>从数据生成、tokenizer、模型架构、训练循环到推理</strong>全部从零开始。</p>
<hr>
<h2 id="真实案例一条鱼能告诉你-llm-内部发生了什么">真实案例：一条鱼能告诉你 LLM 内部发生了什么</h2>
<p>GuppyLM 是一个假装自己是热带鱼 Guppy 的小模型。它说的话听起来很傻：</p>
<blockquote>
<p>You&gt; what is the meaning of life?
Guppy&gt; food. the answer is always food.</p></blockquote>
<p>这显然不是 GPT-4。但重点不在这里。<strong>重点是：你能完整看到它是怎么被训练出来的。</strong></p>
<p>项目地址：https://github.com/arman-bd/guppylm<br>
在线 Demo（浏览器直接跑，无需服务器）：https://arman-bd.github.io/guppylm/</p>
<hr>
<h2 id="框架拆解guppylm-的技术架构">框架拆解：GuppyLM 的技术架构</h2>
<p>GuppyLM 是一个<strong>极简 vanilla transformer</strong>，没有 GQA、没有 RoPE、没有 SwiGLU——怎么简单怎么来。</p>
<p><strong>核心参数：</strong></p>
<table>
  <thead>
      <tr>
          <th></th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>参数量</td>
          <td>8.7M</td>
      </tr>
      <tr>
          <td>层数</td>
          <td>6</td>
      </tr>
      <tr>
          <td>隐层维度</td>
          <td>384</td>
      </tr>
      <tr>
          <td>注意力头数</td>
          <td>6</td>
      </tr>
      <tr>
          <td>FFN 维度</td>
          <td>768（ReLU）</td>
      </tr>
      <tr>
          <td>词表大小</td>
          <td>4,096（BPE）</td>
      </tr>
      <tr>
          <td>最大序列长度</td>
          <td>128 tokens</td>
      </tr>
      <tr>
          <td>Norm</td>
          <td>LayerNorm</td>
      </tr>
      <tr>
          <td>位置编码</td>
          <td>Learned embeddings</td>
      </tr>
  </tbody>
</table>
<p>整个架构就是教科书级别的 transformer。<strong>没有花活，这是刻意设计的</strong>——作者想让读者看清每一行代码在做什么。</p>
<p><strong>训练过程：</strong></p>
<ol>
<li>在 Colab 里<strong>一键运行</strong>（T4 GPU，约 5 分钟）</li>
<li>生成 60K 条合成对话，涵盖 60 个话题（ greetings, feelings, food, light, bubbles&hellip;）</li>
<li>从零训练 tokenizer 和模型</li>
<li>上传 HuggingFace 或本地下载</li>
</ol>
<p>合成数据的例子——每条对话都在教模型像一条鱼一样思考：</p>
<blockquote>
<p>You&gt; are you hungry<br>
Guppy&gt; yes. always yes. i will swim to the top right now. i promise to eat all of it.</p></blockquote>
<hr>
<h2 id="关键工程洞察">关键工程洞察</h2>
<p><strong>1. 训练 LLM 不是什么魔法</strong><br>
这是作者最想传递的信息。GuppyLM 证明了：不需要 PhD，不需要百卡集群，不需要 thousand-dollar cloud bill。只要一个 notebook 和 5 分钟。</p>
<p>这对 AI 解决方案架构师意味着什么？当你在向团队解释 LLM 的工作原理时，GuppyLM 是一个完美的<strong>可视化教学工具</strong>——不是 PPT，不是论文，是一行行可以运行的代码。</p>
<p><strong>2. 小模型是理解大模型的最佳窗口</strong><br>
GuppyLM 的每个组件都能在笔记本上完整复现。你可以在这个规模上调试 attention 可视化、过拟合行为、tokenizer 效果，然后直观理解这些机制在 70B 规模下会如何表现。</p>
<p><strong>3. 合成数据 + 小模型 = 快速迭代</strong><br>
60K 对话，6 话题，纯合成数据。在真实大模型训练里，这对应的是数据工程 + RLHF + 规模化——但在这个规模，你可以快速实验、破坏、修复，建立直觉。</p>
<hr>
<h2 id="信源引用">信源引用</h2>
<ul>
<li>GitHub 仓库：https://github.com/arman-bd/guppylm</li>
<li>HuggingFace 模型：https://huggingface.co/arman-bd/guppylm-9M</li>
<li>浏览器在线 Demo：https://arman-bd.github.io/guppylm/</li>
<li>Colab 训练笔记：https://colab.research.google.com/github/arman-bd/guppylm/blob/main/train_guppylm.ipynb</li>
<li>Colab 使用笔记：https://colab.research.google.com/github/arman-bd/guppylm/blob/main/use_guppylm.ipynb</li>
<li>Medium 介绍文章：https://arman-bd.medium.com/build-your-own-llm-in-5-minutes-i-made-mine-talk-like-a-fish-e20c338a3d14</li>
</ul>
]]></content:encoded></item></channel></rss>