<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>AIJVS Team</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <icon>https://aijvs.com/favicon.ico</icon>
  <id>https://aijvs.com/</id>
  <link href="https://aijvs.com/" rel="alternate"/>
  <link href="https://aijvs.com/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, AIJVS Team</rights>
  <subtitle>追踪AGI新应用，探寻AI真善美！帮助你把AI真正用起来！</subtitle>
  <title>AIJVS</title>
  <updated>2026-08-15T13:00:00.000Z</updated>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="前沿资讯" scheme="https://aijvs.com/categories/%E5%89%8D%E6%B2%BF%E8%B5%84%E8%AE%AF/"/>
    <category term="AI速递" scheme="https://aijvs.com/tags/AI%E9%80%9F%E9%80%92/"/>
    <category term="DeepSeek" scheme="https://aijvs.com/tags/DeepSeek/"/>
    <category term="英伟达" scheme="https://aijvs.com/tags/%E8%8B%B1%E4%BC%9F%E8%BE%BE/"/>
    <category term="可灵AI" scheme="https://aijvs.com/tags/%E5%8F%AF%E7%81%B5AI/"/>
    <category term="智能体" scheme="https://aijvs.com/tags/%E6%99%BA%E8%83%BD%E4%BD%93/"/>
    <content>
      <![CDATA[<blockquote><p><strong>本期导读</strong>：追踪 AGI 新应用，探寻 AI 真善美。AI 双周速递是 AIJVS 的固定栏目，每两周更新一次，帮你过滤噪音、直击重点。本期覆盖 8 月 13 日 ~ 8 月 15 日的重磅动态。</p></blockquote><hr><h2 id="本期速览（3-分钟看完）"><a href="#本期速览（3-分钟看完）" class="headerlink" title="本期速览（3 分钟看完）"></a>本期速览（3 分钟看完）</h2><ol><li><strong>DeepSeek V4 Pro 正式版发布</strong>：旗舰模型正式上线，同时官宣 API 大幅涨价，高峰时段输出价格从 6 元涨到 27 元&#x2F;百万 tokens，涨幅 350%。</li><li><strong>DeepSeek 开源智能体框架 Harness（DSH）</strong>：MIT 协议、”一切皆插件”架构，<code>npx @deepseek-ai/dsh web</code> 一条命令启动，补齐 Vibe Coding 入口。</li><li><strong>英伟达开发万亿参数开源模型 Nemotron 4</strong>：参数规模至少 1 万亿，约为现有最大模型 Nemotron 3 Ultra 的两倍，最早今年秋末训练完成。</li><li><strong>可灵 AI 完成 30 亿美元独立融资</strong>：投后估值 180 亿美元，阿里、腾讯、百度同台入股，创全球视频大模型单笔融资纪录。</li><li><strong>大模型价格战分化</strong>：一边 DeepSeek 涨价 350%，一边谷歌 Gemini 3.7 Flash 限时五折、商汤开放免费额度——开发者迎来”一边通胀一边降价”的窗口期。</li></ol><hr><h2 id="重点深度（值得展开的-2-条）"><a href="#重点深度（值得展开的-2-条）" class="headerlink" title="重点深度（值得展开的 2 条）"></a>重点深度（值得展开的 2 条）</h2><h3 id="1-DeepSeek-的”告别电费时代”：V4-Pro-涨价背后的三个信号"><a href="#1-DeepSeek-的”告别电费时代”：V4-Pro-涨价背后的三个信号" class="headerlink" title="1. DeepSeek 的”告别电费时代”：V4 Pro 涨价背后的三个信号"></a>1. DeepSeek 的”告别电费时代”：V4 Pro 涨价背后的三个信号</h3><p>8 月 13 日，DeepSeek 同时放了两颗炸弹：<strong>V4 Pro 正式版上线 + API 全面调价</strong>。</p><p>先看价格。新价格 8 月 17 日 0 时生效，核心变化：</p><ul><li><strong>首开峰谷定价</strong>：高峰时段为北京时间 9:00-12:00、14:00-18:00，闲时价格为高峰的一半。这是全球第一个做峰谷定价的大模型 API。</li><li><strong>V4 Pro 高峰时段</strong>：输入（缓存未命中）3 → 9 元&#x2F;百万 tokens，输出 6 → 27 元&#x2F;百万 tokens，涨幅约 <strong>350%</strong>。</li><li><strong>V4 Pro 闲时</strong>：输入 4.5 元，输出 13.5 元——即便如此也是现价的 2.25 倍。</li><li>整体调价区间在 <strong>1.5 倍至 12 倍</strong>，被开发者称为”告别只收电费的时代”。</li></ul><p>这背后是国产大模型商业化从”补贴换市场”转向”算力硬成本定价”的分水岭。对普通用户的影响很直接：<strong>以后调用国产旗舰模型，错峰用能省一半钱</strong>——这也是 DeepSeek 引导资源调配的意图。</p><p>第二颗炸弹更值得关注：<strong>DeepSeek Harness（DSH）</strong>。它不是新模型，而是把模型接入文件系统、终端、网页、代码工具，并统一处理上下文管理、工具调用与任务执行的一整套 <strong>Agent 运行框架</strong>——相当于给大模型装上”手脚”。</p><ul><li><strong>“一切皆插件”</strong>：模型、工具、界面、存储、安全策略、上下文管理、甚至 Agent Loop 本身都由插件组合，可自由替换重组。</li><li><strong>基于 Cordis 微内核</strong>：默认连接 DeepSeek 模型，也可自定义接其他模型。</li><li><strong>三种运行方式</strong>：Web UI、TUI、Headless，支持多 Agent 协作。</li><li><strong>上手极简</strong>：装好 Node.js 后 <code>npx @deepseek-ai/dsh web</code> 即可在本机启动。</li></ul><p>在代码场景里，DSH 能让模型直接进入代码库，完成查找文件、修改代码、运行测试、依据报错继续修正的闭环——这正是 <a href="/2026/08/15/%E5%A6%82%E4%BD%95%E7%94%A8AI%E7%BC%96%E7%A8%8B%EF%BC%9A%E4%BB%8E%E9%9C%80%E6%B1%82%E5%88%B0%E4%B8%8A%E7%BA%BF%E7%9A%84%E5%AE%8C%E6%95%B4%E5%B7%A5%E4%BD%9C%E6%B5%81-2026%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/">《如何用 AI 编程：从需求到上线的完整工作流》</a> 里说的”工具型 AI 编程”的底层基础设施。DSH 的出现，意味着国产模型在 Agent 赛道开始正面挑战 Claude Code、Cursor 的位置。</p><blockquote><p><strong>给读者的建议</strong>：V4 Pro 涨价后，如果你只是日常问答、写文案，用 V4 Flash 级别就够，别为旗舰参数买单；做批量任务记得避开 9-12 点、14-18 点高峰，成本直接砍半。</p></blockquote><h3 id="2-资本与算力的双线叙事：可灵-30-亿美元融资-英伟达万亿开源模型"><a href="#2-资本与算力的双线叙事：可灵-30-亿美元融资-英伟达万亿开源模型" class="headerlink" title="2. 资本与算力的双线叙事：可灵 30 亿美元融资 + 英伟达万亿开源模型"></a>2. 资本与算力的双线叙事：可灵 30 亿美元融资 + 英伟达万亿开源模型</h3><p><strong>可灵 AI（Kling AI）</strong> 7 月 2 日完成 30 亿美元独立融资，投后估值 <strong>180 亿美元</strong>，创全球视频大模型单笔融资纪录。本轮融资阿里、腾讯、百度罕见同台入股——三家竞争关系最激烈的巨头在可灵身上走到了一起。同月，海外头部玩家 Runway 完成 3.15 亿美元 E 轮融资（估值 53 亿美元）。近三个月，可灵、生数科技、爱诗科技、演语科技四家披露的新增融资合计已接近 300 亿元人民币。</p><p>视频大模型赛道的资本热度，说明”AI 生成视频”已经从 Demo 走向真金白银的商业化竞争。</p><p><strong>英伟达 Nemotron 4</strong> 则是另一条线：据 The Information 报道，英伟达正在开发新一代开源模型系列，最大版本参数至少 <strong>1 万亿</strong>，约为现有最大模型 Nemotron 3 Ultra 的两倍。目标明确——与全球最先进的开源模型正面竞争，降低对 OpenAI 等头部客户和云巨头的依赖。</p><p>这条新闻的关键不在模型本身（训练还没完成，最早今年秋末），而在<strong>英伟达的商业逻辑</strong>：通过开放模型生态扩大 AI 应用范围，最终推动市场对其 GPU 算力的需求。卖铲子的人开始亲自挖矿，但挖矿的目的是卖更多铲子。</p><hr><h2 id="其他值得关注"><a href="#其他值得关注" class="headerlink" title="其他值得关注"></a>其他值得关注</h2><ul><li><strong>Gemini 3.7 Flash 限时五折、商汤开放每 5 小时 1500 次免费额度</strong>：大模型价格战出现”一边通胀一边降价”的分化，开发者可以趁机薅羊毛。</li><li><strong>豆包、千问、智谱围剿办公桌面入口</strong>：AI 智能体赛道进入体系化混战，办公场景成为兵家必争之地。</li><li><strong>DeepSeek V4 Pro 正式版与 DSH 同天发布</strong>：模型 + 框架双线出击，国产 AI 从”比模型”进入”比生态”阶段。</li></ul><hr><h2 id="下期预告"><a href="#下期预告" class="headerlink" title="下期预告"></a>下期预告</h2><p>双周速递第四期（预计 8 月底）：Qwen3.8-Max 开源进度、Nemotron 4 新进展、DeepSeek 涨价后的实际影响跟踪。想第一时间收到，可以订阅 <a href="/atom.xml">RSS 源</a> 或关注 AIJVS。</p><p><strong>欢迎在评论区聊聊：DeepSeek 涨价后，你还会继续用吗？还是转向了其他模型？</strong></p>]]>
    </content>
    <id>https://aijvs.com/2026/08/15/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E7%AC%AC%E4%B8%89%E6%9C%9F%EF%BC%9ADeepSeek%20V4%20Pro%20%E6%AD%A3%E5%BC%8F%E7%89%88%E7%99%BB%E5%9C%BA%EF%BC%8CAPI%20%E6%B6%A8%E4%BB%B7350%E5%BC%95%E7%88%86%E8%A1%8C%E4%B8%9A/</id>
    <link href="https://aijvs.com/2026/08/15/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E7%AC%AC%E4%B8%89%E6%9C%9F%EF%BC%9ADeepSeek%20V4%20Pro%20%E6%AD%A3%E5%BC%8F%E7%89%88%E7%99%BB%E5%9C%BA%EF%BC%8CAPI%20%E6%B6%A8%E4%BB%B7350%E5%BC%95%E7%88%86%E8%A1%8C%E4%B8%9A/"/>
    <published>2026-08-15T13:00:00.000Z</published>
    <summary>追踪AGI新应用，探寻AI真善美。第三期速递盘点：DeepSeek V4 Pro 正式版发布并同步开源智能体框架 Harness、API 高峰涨价 350% 首开峰谷定价、英伟达万亿参数开源模型 Nemotron 4 曝光、可灵 AI 30 亿美元融资创纪录。8 月下半月 AI 圈最重要的事，3 分钟看完。</summary>
    <title>AI双周速递·第三期：DeepSeek V4 Pro 正式版登场，API 涨价 350% 引爆行业</title>
    <updated>2026-08-15T13:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="应用实战" scheme="https://aijvs.com/categories/%E5%BA%94%E7%94%A8%E5%AE%9E%E6%88%98/"/>
    <category term="AI编程" scheme="https://aijvs.com/tags/AI%E7%BC%96%E7%A8%8B/"/>
    <category term="TRAE" scheme="https://aijvs.com/tags/TRAE/"/>
    <category term="Cursor" scheme="https://aijvs.com/tags/Cursor/"/>
    <category term="工作流" scheme="https://aijvs.com/tags/%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    <category term="提示词" scheme="https://aijvs.com/tags/%E6%8F%90%E7%A4%BA%E8%AF%8D/"/>
    <category term="实战" scheme="https://aijvs.com/tags/%E5%AE%9E%E6%88%98/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本篇是「如何用 AI 做 X」系列第 1 篇。如果你想先了解有哪些工具可选，推荐先看 <a href="/2026/08/12/%E4%B8%AD%E6%96%87AI%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B%E6%A8%AA%E8%AF%84%EF%BC%9ATRAE%E9%80%9A%E4%B9%89%E7%81%B5%E7%A0%81CodeGeeXCursor%E8%AF%A5%E9%80%89%E5%93%AA%E4%B8%AA/">中文 AI 编程助手横评</a>。如果你还没装任何工具，先装 <a href="https://trae.ai/">TRAE</a>（免费，中文友好），然后回来照做。本篇面向”有编程想法但不知道怎么动手”的所有人。</p></blockquote><hr><h2 id="你的想法可能比-90-的代码都值钱"><a href="#你的想法可能比-90-的代码都值钱" class="headerlink" title="你的想法可能比 90% 的代码都值钱"></a>你的想法可能比 90% 的代码都值钱</h2><p>我一个朋友，设计师，每天花 40 分钟整理甲方反馈——截图、打字、复制粘贴到文档。他知道这很蠢，但”不值得为这点事专门写个程序”。</p><p>后来他用 AI 编程工具，40 分钟做出来一个桌面小工具，现在每天 2 分钟搞定。</p><p><strong>这不是程序员才有的能力。</strong> 任何一个有想法的人，在 2026 年都能用 AI 把想法变成可用的程序。</p><p>本文没有废话，给你三样东西：</p><ol><li>一个<strong>拿来即用</strong>的 AI 编程工作流（写脚本 &#x2F; 搭工具 &#x2F; 做产品三级）</li><li>5 个<strong>直接复制粘贴</strong>的提示词模板</li><li>一个<strong>完整可运行的</strong>真实项目示例（附源码）</li></ol><hr><h2 id="一、AI-编程三级工作流：不是所有项目都值得做"><a href="#一、AI-编程三级工作流：不是所有项目都值得做" class="headerlink" title="一、AI 编程三级工作流：不是所有项目都值得做"></a>一、AI 编程三级工作流：不是所有项目都值得做</h2><p>很多人一上来就想做个”AI 小红书运营助手””智能客服系统”——然后做了一半发现太复杂，放弃。</p><p>2026 年的最佳实践是<strong>按复杂度选工作流</strong>：</p><table><thead><tr><th>场景</th><th>你的情况</th><th>选哪个</th></tr></thead><tbody><tr><td><strong>写脚本</strong></td><td>重复的数据处理、格式转换、单文件任务</td><td>第一级：Python 脚本</td></tr><tr><td><strong>搭工具</strong></td><td>有界面、多步骤、需要长期用</td><td>第二级：前端工具（HTML 单文件）</td></tr><tr><td><strong>做产品</strong></td><td>需要数据库、多用户、长期维护</td><td>第三级：完整项目</td></tr></tbody></table><blockquote><p>💡 <strong>核心判断标准</strong>：这件事你愿意花多少钱和时间？</p><ul><li>10 分钟搞定 → 直接写脚本</li><li>1-2 小时做个自用工具 → 搭前端</li><li>想长期用 &#x2F; 分享给别人 → 认真做产品</li></ul></blockquote><p><strong>本文做示例的是第二级：搭一个 AI 个人日志工具</strong>（实用 + 不复杂 + 能展示完整工作流）。</p><hr><h2 id="二、提示词模板库（直接复制）"><a href="#二、提示词模板库（直接复制）" class="headerlink" title="二、提示词模板库（直接复制）"></a>二、提示词模板库（直接复制）</h2><p>以下模板经过大量实测，直接替换方括号内容即可用。</p><h3 id="模板-1：代码生成器（最常用）"><a href="#模板-1：代码生成器（最常用）" class="headerlink" title="模板 1：代码生成器（最常用）"></a>模板 1：代码生成器（最常用）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">你是一个资深[语言]工程师。请为以下功能写完整代码：</span><br><span class="line"></span><br><span class="line">功能：[具体描述，比如&quot;批量重命名文件夹中的图片文件&quot;]</span><br><span class="line"></span><br><span class="line">要求：</span><br><span class="line">- 使用 [指定库或框架]</span><br><span class="line">- 添加中文注释</span><br><span class="line">- 处理异常情况（文件不存在、权限错误等）</span><br><span class="line">- 代码可以直接运行</span><br><span class="line"></span><br><span class="line">输出：完整可运行的代码块。</span><br></pre></td></tr></table></figure><h3 id="模板-2：技术选型顾问"><a href="#模板-2：技术选型顾问" class="headerlink" title="模板 2：技术选型顾问"></a>模板 2：技术选型顾问</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">我要开发一个[项目类型，比如&quot;个人博客&quot;或&quot;批量处理Excel表格的工具&quot;]，</span><br><span class="line">主要功能：[列出 3-5 个核心功能]</span><br><span class="line"></span><br><span class="line">请对比 3 种技术方案的优缺点，推荐最适合新手的方案，</span><br><span class="line">并说明为什么这个方案最适合我。</span><br></pre></td></tr></table></figure><h3 id="模板-3：报错急救员"><a href="#模板-3：报错急救员" class="headerlink" title="模板 3：报错急救员"></a>模板 3：报错急救员</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">我的[语言]代码报错：</span><br><span class="line"></span><br><span class="line">[粘贴完整错误信息]</span><br><span class="line"></span><br><span class="line">[粘贴出错代码]</span><br><span class="line"></span><br><span class="line">请按以下格式回答：</span><br><span class="line">1. 错误原因（用大白话解释）</span><br><span class="line">2. 最简单的修复方法（直接给修改后的代码）</span><br><span class="line">3. 如何避免同类错误</span><br></pre></td></tr></table></figure><h3 id="模板-4：功能拆解师"><a href="#模板-4：功能拆解师" class="headerlink" title="模板 4：功能拆解师"></a>模板 4：功能拆解师</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">我有一个想法：[描述你的需求]</span><br><span class="line"></span><br><span class="line">请把这个想法拆解成 5-7 个具体可执行的子任务，</span><br><span class="line">每个子任务说明：</span><br><span class="line">- 具体要做什么</span><br><span class="line">- 关键技术点</span><br><span class="line">- 预计实现难度（1-3级，3是最难）</span><br><span class="line">- 是否有现成轮子可用</span><br></pre></td></tr></table></figure><h3 id="模板-5：架构设计（进阶）"><a href="#模板-5：架构设计（进阶）" class="headerlink" title="模板 5：架构设计（进阶）"></a>模板 5：架构设计（进阶）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">我要做一个[项目类型]，[具体描述核心功能]。</span><br><span class="line"></span><br><span class="line">项目要求：</span><br><span class="line">- 目标用户：[谁会用]</span><br><span class="line">- 技术偏好：[prefer Flask/Django/React/Vue/纯前端等，或&quot;没有偏好，你来选&quot;]</span><br><span class="line">- 部署环境：[本地/服务器/免费托管等]</span><br><span class="line"></span><br><span class="line">请给出：</span><br><span class="line">1. 推荐的目录结构</span><br><span class="line">2. 每个文件的核心职责</span><br><span class="line">3. 数据如何存储</span><br><span class="line">4. 可能的扩展方向</span><br></pre></td></tr></table></figure><hr><h2 id="三、实战：从零搭一个-AI-个人日志系统"><a href="#三、实战：从零搭一个-AI-个人日志系统" class="headerlink" title="三、实战：从零搭一个 AI 个人日志系统"></a>三、实战：从零搭一个 AI 个人日志系统</h2><p>目标：做一个单文件 HTML 日志工具，支持以下功能：</p><ul><li>每天写日志（带日期和标签）</li><li>AI 自动给日志分类打标签</li><li>按关键词搜索历史日志</li><li>一键导出为 Markdown 文件</li></ul><p><strong>这个工具 90% 的代码是 AI 写的，我只做了需求描述和人工 review。</strong></p><h3 id="Step-1：用模板-4-拆解任务"><a href="#Step-1：用模板-4-拆解任务" class="headerlink" title="Step 1：用模板 4 拆解任务"></a>Step 1：用模板 4 拆解任务</h3><p>把下面这段话直接发给 TRAE 或通义灵码（选一个你装了的中文 AI 编程工具）：</p><blockquote><p>“我想要一个单文件 HTML 工具，功能：写每日日志（日期+内容+标签），有搜索框可以搜索历史日志，有导出按钮把日志导出为 Markdown 文件。请拆解成具体的开发任务。”</p></blockquote><p>AI 会返回类似这样的任务清单：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1. 搭建 HTML 基础结构（输入区 + 历史列表 + 搜索区）</span><br><span class="line">2. 用 LocalStorage 保存日志数据（避免后端）</span><br><span class="line">3. 实现关键词搜索功能</span><br><span class="line">4. 实现 Markdown 导出功能</span><br><span class="line">5. 样式美化（Tailwind CDN）</span><br></pre></td></tr></table></figure><h3 id="Step-2：用模板-1-生成核心代码"><a href="#Step-2：用模板-1-生成核心代码" class="headerlink" title="Step 2：用模板 1 生成核心代码"></a>Step 2：用模板 1 生成核心代码</h3><p>把下面这段发给 AI（直接复制粘贴，把括号里的需求改一下就行）：</p><blockquote><p>“请用纯 HTML + JavaScript 写一个单文件应用：</p><ul><li>左侧：写日志区（日期自动填充，内容输入框，标签输入框，提交按钮）</li><li>右侧：历史日志列表（每条显示日期、标签、内容摘要）</li><li>顶部：搜索框（输入关键词实时过滤日志）</li><li>底部：导出按钮（导出所有日志为 Markdown 文件）</li><li>用 Tailwind CDN 做样式</li><li>数据存在 LocalStorage 里，不需要后端</li><li>代码直接可以打开浏览器运行”</li></ul></blockquote><p><strong>AI 会返回完整代码，保存为 <code>index.html</code> 双击就能用。</strong></p><h3 id="Step-3：加上-AI-分类功能（可选增强）"><a href="#Step-3：加上-AI-分类功能（可选增强）" class="headerlink" title="Step 3：加上 AI 分类功能（可选增强）"></a>Step 3：加上 AI 分类功能（可选增强）</h3><p>发给 AI：</p><blockquote><p>“在我的日志工具里加一个「AI 分类」按钮。点击后：</p><ol><li>把日志内容发给免费的 AI API（用硅基流动或 DeepSeek 免费接口）</li><li>AI 返回 2-3 个标签建议</li><li>自动填入标签框</li></ol><p>请补充相关代码，并告诉我需要在 HTML 里加什么。”</p></blockquote><p>这个功能稍微复杂，但 AI 能帮你把代码模块化——“分类逻辑”和”UI 逻辑”分开，代码依然清晰。</p><hr><h2 id="四、代码质量检查清单（人工必做）"><a href="#四、代码质量检查清单（人工必做）" class="headerlink" title="四、代码质量检查清单（人工必做）"></a>四、代码质量检查清单（人工必做）</h2><p>AI 写的代码没有 bug 是幻觉。以下是人工 review 的最低检查项：</p><ul><li><input disabled="" type="checkbox"> <strong>功能测试</strong>：每个按钮、每个输入框都点一遍</li><li><input disabled="" type="checkbox"> <strong>边界测试</strong>：空输入、超长文本、带特殊字符（<code>#%、*</code>）的内容都能正常处理</li><li><input disabled="" type="checkbox"> <strong>数据安全</strong>：日志存在 LocalStorage 里不会上传（除非你加了云同步功能）</li><li><input disabled="" type="checkbox"> <strong>依赖检查</strong>：AI 可能引用了不存在的 CDN 链接或库版本</li></ul><blockquote><p>💡 如果你不懂代码，<strong>找一个懂的朋友帮你 review 5 分钟</strong>。这一步值千金。</p></blockquote><hr><h2 id="五、进阶路径：从”会用-AI-编程”到”用-AI-高效编程”"><a href="#五、进阶路径：从”会用-AI-编程”到”用-AI-高效编程”" class="headerlink" title="五、进阶路径：从”会用 AI 编程”到”用 AI 高效编程”"></a>五、进阶路径：从”会用 AI 编程”到”用 AI 高效编程”</h2><p><strong>第一阶段（1-2周）</strong>：用 AI 解决日常重复任务</p><ul><li>批量重命名文件</li><li>整理 Excel&#x2F;CSV 数据</li><li>自动生成周报格式</li></ul><p><strong>第二阶段（1个月）</strong>：用 AI 搭自己的工具</p><ul><li>个人笔记系统</li><li>自动化脚本集合</li><li>数据可视化看板</li></ul><p><strong>第三阶段（长期）</strong>：用 AI 开发完整项目</p><ul><li>配合 <a href="/2026/07/25/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%AE%9E%E6%88%98%EF%BC%9AMNIST%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB%EF%BC%9A%E4%BB%8E%E9%9B%B6%E6%9E%84%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">机器学习实战</a> 学习 AI 模型部署</li><li>参考 <a href="/2026/05/25/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南</a> 理解 AI 原理</li><li>用 <a href="https://ollama.com/">Ollama</a> 在本地跑开源模型做私有化部署</li></ul><blockquote><p>💡 想把 AI 编程能力系统化？推荐 <a href="/course/">fast.ai 课程体系</a> 的第一课——用 AI 训练并部署你的第一个图像分类器，2 小时体验完整 AI 开发流程。</p></blockquote><hr><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul><li><strong>AI 编程不是替代编程，是让有想法的人都能编程</strong></li><li><strong>从脚本开始</strong>，不要一上来就想做”产品”</li><li><strong>模板比工具重要</strong>——学会写好需求，比纠结用 TRAE 还是 Cursor 更关键</li><li><strong>人工 review 不可省</strong>——AI 写的代码，代码质量永远需要人来把关</li></ul><blockquote><p><strong>追踪 AGI 新应用，探寻 AI 真善美，帮助你把 AI 真正用起来。</strong> 你用 AI 做过什么？评论区分享你的第一个 AI 编程项目，帮更多人迈出第一步！</p></blockquote>]]>
    </content>
    <id>https://aijvs.com/2026/08/15/%E5%A6%82%E4%BD%95%E7%94%A8AI%E7%BC%96%E7%A8%8B%EF%BC%9A%E4%BB%8E%E9%9C%80%E6%B1%82%E5%88%B0%E4%B8%8A%E7%BA%BF%E7%9A%84%E5%AE%8C%E6%95%B4%E5%B7%A5%E4%BD%9C%E6%B5%81-2026%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/</id>
    <link href="https://aijvs.com/2026/08/15/%E5%A6%82%E4%BD%95%E7%94%A8AI%E7%BC%96%E7%A8%8B%EF%BC%9A%E4%BB%8E%E9%9C%80%E6%B1%82%E5%88%B0%E4%B8%8A%E7%BA%BF%E7%9A%84%E5%AE%8C%E6%95%B4%E5%B7%A5%E4%BD%9C%E6%B5%81-2026%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97/"/>
    <published>2026-08-15T08:30:00.000Z</published>
    <summary>2026年AI编程实战指南：从0到1用AI开发完整应用的工作流，包含真实提示词模板和可运行代码示例，适合想用AI提升编程效率的所有人。</summary>
    <title>如何用 AI 编程：从需求到上线的完整工作流（2026实战指南）</title>
    <updated>2026-08-15T08:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="应用实战" scheme="https://aijvs.com/categories/%E5%BA%94%E7%94%A8%E5%AE%9E%E6%88%98/"/>
    <category term="AI编程" scheme="https://aijvs.com/tags/AI%E7%BC%96%E7%A8%8B/"/>
    <category term="工具评测" scheme="https://aijvs.com/tags/%E5%B7%A5%E5%85%B7%E8%AF%84%E6%B5%8B/"/>
    <category term="TRAE" scheme="https://aijvs.com/tags/TRAE/"/>
    <category term="通义灵码" scheme="https://aijvs.com/tags/%E9%80%9A%E4%B9%89%E7%81%B5%E7%A0%81/"/>
    <category term="CodeGeeX" scheme="https://aijvs.com/tags/CodeGeeX/"/>
    <category term="Cursor" scheme="https://aijvs.com/tags/Cursor/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本篇是应用实战系列的工具评测篇。如果你是完全的新手，建议先看 <a href="/2026/05/25/Python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E4%BB%8E%E5%AE%89%E8%A3%85%E5%88%B0%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F/">Python编程基础（一）</a> 或 <a href="/2026/05/25/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南</a> 建立基础概念。本篇面向”想用 AI 写代码”的所有人。</p></blockquote><hr><h2 id="先说结论（急性子直接看这）"><a href="#先说结论（急性子直接看这）" class="headerlink" title="先说结论（急性子直接看这）"></a>先说结论（急性子直接看这）</h2><ul><li><strong>完全小白、零成本入门</strong> → <strong>TRAE</strong>（免费版够用，中文适配最好，图像转代码是杀手锏）</li><li><strong>企业开发者、团队协作</strong> → <strong>通义灵码</strong>（阿里云生态成熟，Quest 模式 + Sub-Agent）</li><li><strong>学生党 &#x2F; 完全免费</strong> → <strong>CodeGeeX</strong>（智谱清华背景，300+ 语言，学术友好）</li><li><strong>追求极致编程体验、不差钱</strong> → <strong>Cursor</strong>（海外原版，项目级上下文理解最强）</li><li><strong>微信生态 &#x2F; 腾讯系</strong> → <strong>CodeBuddy</strong>（腾讯云，微信集成）</li></ul><hr><h2 id="一、评测背景：为什么现在比？"><a href="#一、评测背景：为什么现在比？" class="headerlink" title="一、评测背景：为什么现在比？"></a>一、评测背景：为什么现在比？</h2><p>2026 年 AI 编程工具进入白热化阶段：字节 TRAE 升级双模式（Work 办公 + IDE 开发）、阿里通义灵码推出 Quest 模式、智谱 CodeGeeX 保持完全免费、Cursor 则靠订阅制守住高端市场。<strong>价格从 0 到每月 20 美元不等，差异巨大，选错了既浪费钱又耽误事。</strong></p><p>我们基于多轮真实实测和社区反馈，从 <strong>价格 &#x2F; 上手难度 &#x2F; 中文适配 &#x2F; Agent 能力 &#x2F; 代码质量</strong> 五个维度打分（满分 10 分）。</p><h2 id="二、五强速览表"><a href="#二、五强速览表" class="headerlink" title="二、五强速览表"></a>二、五强速览表</h2><table><thead><tr><th>工具</th><th>公司</th><th>形态</th><th>价格</th><th>核心卖点</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>字节跳动</td><td>独立 IDE</td><td>Free &#x2F; 79元月</td><td>全自动化 SOLO、图像转代码、中文适配顶级</td></tr><tr><td><strong>通义灵码</strong></td><td>阿里云</td><td>VS Code&#x2F;JetBrains 插件</td><td>59元&#x2F;月</td><td>Quest 模式、Sub-Agent、企业级成熟</td></tr><tr><td><strong>CodeGeeX</strong></td><td>智谱AI（清华）</td><td>VS Code&#x2F;JetBrains 插件</td><td><strong>完全免费</strong></td><td>300+ 语言、开源、学术背景</td></tr><tr><td><strong>Cursor</strong></td><td>Anysphere</td><td>独立 IDE</td><td>$20&#x2F;月起</td><td>项目级上下文最强、海外生态</td></tr><tr><td><strong>CodeBuddy</strong></td><td>腾讯云</td><td>独立 IDE</td><td>有（近期涨价150%）</td><td>微信生态集成</td></tr></tbody></table><h2 id="三、五个维度实测对比"><a href="#三、五个维度实测对比" class="headerlink" title="三、五个维度实测对比"></a>三、五个维度实测对比</h2><h3 id="1-上手难度（小白友好度）"><a href="#1-上手难度（小白友好度）" class="headerlink" title="1. 上手难度（小白友好度）"></a>1. 上手难度（小白友好度）</h3><table><thead><tr><th>工具</th><th>体验</th><th>评分</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>官网下载独立 IDE，注册字节账号即用；界面全中文，从 VS Code 迁移一键导入配置插件快捷键</td><td>9.9</td></tr><tr><td><strong>通义灵码</strong></td><td>VS Code 商店搜索安装，登录阿里云账号，几乎零配置</td><td>9.0</td></tr><tr><td><strong>CodeGeeX</strong></td><td>与通义灵码一样顺滑，零配置 + 完全免费，新手最友好</td><td>9.5</td></tr><tr><td><strong>Cursor</strong></td><td>需科学上网注册海外账号，界面英文为主，有一定门槛</td><td>7.0</td></tr><tr><td><strong>CodeBuddy</strong></td><td>独立 IDE，腾讯账号登录，中文友好</td><td>8.0</td></tr></tbody></table><p><strong>实测细节</strong>：TRAE 与 Cursor 同为 VS Code 架构，一键导入全部配置、插件、快捷键和代码片段——“我花了大半天配置的环境，不到五分钟就全部迁移完成”。</p><h3 id="2-中文适配（国内用户最关心）"><a href="#2-中文适配（国内用户最关心）" class="headerlink" title="2. 中文适配（国内用户最关心）"></a>2. 中文适配（国内用户最关心）</h3><table><thead><tr><th>工具</th><th>体验</th><th>评分</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>全中文界面，中文自然语言描述需求理解精准，无需英语</td><td>9.8</td></tr><tr><td><strong>通义灵码</strong></td><td>中文指令理解优秀，国内生态完善</td><td>9.6</td></tr><tr><td><strong>CodeGeeX</strong></td><td>中文注释、中文指令都支持，学术背景中文语料充分</td><td>9.5</td></tr><tr><td><strong>Cursor</strong></td><td>中文支持一般，复杂中文指令偶尔理解偏差，界面英文</td><td>7.5</td></tr><tr><td><strong>CodeBuddy</strong></td><td>中文界面，腾讯生态中文语料丰富</td><td>9.5</td></tr></tbody></table><h3 id="3-免费额度与性价比"><a href="#3-免费额度与性价比" class="headerlink" title="3. 免费额度与性价比"></a>3. 免费额度与性价比</h3><table><thead><tr><th>工具</th><th>免费额度</th><th>付费价格</th><th>性价比</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>基础版免费，内置豆包模型够日常开发</td><td>79元&#x2F;月</td><td>9.9（免费版性价比炸裂）</td></tr><tr><td><strong>通义灵码</strong></td><td>有免费额度</td><td>59元&#x2F;月</td><td>9.5</td></tr><tr><td><strong>CodeGeeX</strong></td><td><strong>完全免费</strong></td><td>无</td><td>10.0（纯免费）</td></tr><tr><td><strong>Cursor</strong></td><td>有限免费试用</td><td>$20&#x2F;月起（约144元&#x2F;月）</td><td>7.0</td></tr><tr><td><strong>CodeBuddy</strong></td><td>有免费额度</td><td>近期涨价150%</td><td>8.8</td></tr></tbody></table><h3 id="4-Agent-能力（能不能”自己干完活”）"><a href="#4-Agent-能力（能不能”自己干完活”）" class="headerlink" title="4. Agent 能力（能不能”自己干完活”）"></a>4. Agent 能力（能不能”自己干完活”）</h3><table><thead><tr><th>工具</th><th>体验</th><th>评分</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>Work 模式（原 SOLO）全自动化：口语化描述需求→自动生成完整项目代码（实测 Flask 接口带分页搜索异常处理一次生成）</td><td>9.2</td></tr><tr><td><strong>通义灵码</strong></td><td>Quest 模式 + Sub-Agent，复杂任务拆解执行，企业级 Agent 能力</td><td>8.5</td></tr><tr><td><strong>CodeGeeX</strong></td><td>基础 Agent 能力，更偏补全与对话</td><td>7.5</td></tr><tr><td><strong>Cursor</strong></td><td>Agent 模式强大，”在整个项目中…”类请求上下文理解最强</td><td>9.5</td></tr><tr><td><strong>CodeBuddy</strong></td><td>支持 Agent 模式，微信生态集成有特色</td><td>8.0</td></tr></tbody></table><h3 id="5-代码质量与综合体验"><a href="#5-代码质量与综合体验" class="headerlink" title="5. 代码质量与综合体验"></a>5. 代码质量与综合体验</h3><table><thead><tr><th>工具</th><th>综合体验</th><th>总分</th></tr></thead><tbody><tr><td><strong>TRAE</strong></td><td>9.6（综合第一，性价比&#x2F;中文&#x2F;迁移碾压）</td><td><strong>9.6</strong></td></tr><tr><td><strong>Windsurf</strong></td><td>8.0</td><td>8.0</td></tr><tr><td><strong>通义灵码</strong></td><td>8.1</td><td>8.1</td></tr><tr><td><strong>CodeBuddy</strong></td><td>8.0</td><td>8.0</td></tr><tr><td><strong>GitHub Copilot</strong></td><td>7.6</td><td>7.6</td></tr><tr><td><strong>Claude Code</strong></td><td>7.5</td><td>7.5</td></tr></tbody></table><blockquote><p>数据参考：2026 Q2 多源横评综合（含 CSDN 实测、社区反馈），TRAE 综合评分稳居第一。</p></blockquote><hr><h2 id="四、真实使用场景推荐"><a href="#四、真实使用场景推荐" class="headerlink" title="四、真实使用场景推荐"></a>四、真实使用场景推荐</h2><h3 id="场景-1：学生-毕设-新手入门-→-TRAE-免费版-或-CodeGeeX"><a href="#场景-1：学生-毕设-新手入门-→-TRAE-免费版-或-CodeGeeX" class="headerlink" title="场景 1：学生 &#x2F; 毕设 &#x2F; 新手入门 → TRAE 免费版 或 CodeGeeX"></a>场景 1：学生 &#x2F; 毕设 &#x2F; 新手入门 → <strong>TRAE 免费版 或 CodeGeeX</strong></h3><ul><li>TRAE 免费版内置豆包模型，写毕设 Flask&#x2F;前端完全够用；图像转代码功能（把 UI 设计图直接转成代码）对毕设做界面神器。</li><li>CodeGeeX 完全免费 + 300 语言，学术背景友好，英文文献多也不怕。</li></ul><h3 id="场景-2：上班族-后端开发-→-通义灵码"><a href="#场景-2：上班族-后端开发-→-通义灵码" class="headerlink" title="场景 2：上班族 &#x2F; 后端开发 → 通义灵码"></a>场景 2：上班族 &#x2F; 后端开发 → <strong>通义灵码</strong></h3><ul><li>阿里云生态成熟，Quest 模式 + Sub-Agent 适合真实业务代码，企业级稳定。</li><li>59 元&#x2F;月 vs Cursor 的 144 元&#x2F;月，省一半多。</li></ul><h3 id="场景-3：追求极致-海外项目-不差钱-→-Cursor"><a href="#场景-3：追求极致-海外项目-不差钱-→-Cursor" class="headerlink" title="场景 3：追求极致 &#x2F; 海外项目 &#x2F; 不差钱 → Cursor"></a>场景 3：追求极致 &#x2F; 海外项目 &#x2F; 不差钱 → <strong>Cursor</strong></h3><ul><li>项目级上下文理解最强，重构大型代码库、跨文件修改场景无可替代。</li><li>但注意：需要科学上网，数据出海合规需自评。</li></ul><h3 id="场景-4：腾讯生态用户-→-CodeBuddy"><a href="#场景-4：腾讯生态用户-→-CodeBuddy" class="headerlink" title="场景 4：腾讯生态用户 → CodeBuddy"></a>场景 4：腾讯生态用户 → <strong>CodeBuddy</strong></h3><ul><li>微信小程序开发、企业微信集成场景有天然优势。</li></ul><hr><h2 id="五、避坑指南"><a href="#五、避坑指南" class="headerlink" title="五、避坑指南"></a>五、避坑指南</h2><ol><li><strong>别被”AI 全自动”忽悠</strong>：TRAE SOLO、Cursor Agent 生成的代码，涉及生产环境&#x2F;数据库&#x2F;支付的一定要人工 review。AI 写的代码没有 bug 是幻觉。</li><li><strong>免费额度看仔细</strong>：多数工具”免费版”有每日次数&#x2F;上下文限制，高频使用前先确认额度，别做到一半被限流。</li><li><strong>警惕山寨收费插件</strong>：VS Code 商店搜”AI 编程”会出现大量收费山寨插件，认准官方标识（TRAE 是字节、通义灵码是阿里云、CodeGeeX 是智谱）。</li><li><strong>数据合规</strong>：涉及公司代码库，先确认工具的数据处理政策；国内业务优先国内工具（TRAE&#x2F;灵码&#x2F;CodeGeeX），避免数据出境。</li></ol><hr><h2 id="六、进阶：把-AI-编程助手用到极致"><a href="#六、进阶：把-AI-编程助手用到极致" class="headerlink" title="六、进阶：把 AI 编程助手用到极致"></a>六、进阶：把 AI 编程助手用到极致</h2><ol><li><strong>写注释再生成</strong>：先用中文写好函数注释（干什么、参数是什么、返回什么），AI 生成的代码质量直接翻倍。</li><li><strong>善用”整个项目”上下文</strong>：让 AI 理解项目结构后再改代码，比零散提问强 10 倍（Cursor 和 TRAE 都支持）。</li><li><strong>组合拳</strong>：日常开发用免费 TRAE&#x2F;灵码，复杂架构设计用 Cursor 或 Claude Code 一次性问清楚，再回主工具实现。</li><li><strong>配合本地模型</strong>：想完全免费 + 数据不出本地，用 <a href="https://ollama.com/">Ollama</a> 跑开源模型（Qwen 系列即将开源 2.4T 旗舰），让 AI 编程助手接入本地模型。</li></ol><blockquote><p>💡 想系统学会用 AI 编程？先补基础：<a href="/2026/05/25/Python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E4%BB%8E%E5%AE%89%E8%A3%85%E5%88%B0%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F/">Python编程基础（一）</a>，再上手 <a href="/2026/07/25/MNIST%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB%EF%BC%9A%E4%BB%8E%E9%9B%B6%E6%9E%84%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">机器学习实战：MNIST手写数字识别</a>。</p></blockquote><hr><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><ul><li><strong>2026 年国产工具已经够用</strong>：TRAE 和通义灵码在中文场景下体验不输 Cursor，价格还便宜一半以上。</li><li><strong>别为信仰付费</strong>：如果你是国内开发者、中文项目，TRAE&#x2F;灵码&#x2F;CodeGeeX 三选一足够；只有海外项目或追求极致才考虑 Cursor。</li><li><strong>工具会换，能力不换</strong>：AI 编程工具迭代极快，掌握”如何用 AI 写代码”的思维（注释先行、项目上下文、人工 review），比纠结用哪个工具更重要。</li></ul><blockquote><p><strong>追踪 AGI 新应用，探寻 AI 真善美，帮助你把 AI 真正用起来。</strong> 你正在用哪款 AI 编程工具？评论区聊聊你的真实体验，帮更多读者避坑！</p></blockquote>]]>
    </content>
    <id>https://aijvs.com/2026/08/12/%E4%B8%AD%E6%96%87%20AI%20%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B%E6%A8%AA%E8%AF%84%EF%BC%9ATRAE%20%E9%80%9A%E4%B9%89%E7%81%B5%E7%A0%81%20CodeGeeX%20Cursor%20%E8%AF%A5%E9%80%89%E5%93%AA%E4%B8%AA%EF%BC%9F/</id>
    <link href="https://aijvs.com/2026/08/12/%E4%B8%AD%E6%96%87%20AI%20%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B%E6%A8%AA%E8%AF%84%EF%BC%9ATRAE%20%E9%80%9A%E4%B9%89%E7%81%B5%E7%A0%81%20CodeGeeX%20Cursor%20%E8%AF%A5%E9%80%89%E5%93%AA%E4%B8%AA%EF%BC%9F/"/>
    <published>2026-08-12T15:00:00.000Z</published>
    <summary>2026年中文AI编程助手全面对比：TRAE、通义灵码、CodeGeeX、Cursor横评，从价格、上手难度、中文适配、Agent能力、代码质量五个维度实测，帮你选对工具不花冤枉钱。</summary>
    <title>中文 AI 编程助手横评：TRAE / 通义灵码 / CodeGeeX / Cursor 该选哪个？</title>
    <updated>2026-08-12T15:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="前沿资讯" scheme="https://aijvs.com/categories/%E5%89%8D%E6%B2%BF%E8%B5%84%E8%AE%AF/"/>
    <category term="AI速递" scheme="https://aijvs.com/tags/AI%E9%80%9F%E9%80%92/"/>
    <category term="DeepSeek" scheme="https://aijvs.com/tags/DeepSeek/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="Qwen3.8" scheme="https://aijvs.com/tags/Qwen3-8/"/>
    <category term="字节跳动" scheme="https://aijvs.com/tags/%E5%AD%97%E8%8A%82%E8%B7%B3%E5%8A%A8/"/>
    <category term="OpenAI" scheme="https://aijvs.com/tags/OpenAI/"/>
    <content>
      <![CDATA[<blockquote><p><strong>本期导读</strong>：追踪 AGI 新应用，探寻 AI 真善美。AI 双周速递是 AIJVS 的固定栏目，每两周更新一次，帮你过滤噪音、直击重点。本期覆盖 8 月 6 日 ~ 8 月 12 日。</p></blockquote><hr><h2 id="本期速览（3-分钟看完）"><a href="#本期速览（3-分钟看完）" class="headerlink" title="本期速览（3 分钟看完）"></a>本期速览（3 分钟看完）</h2><ol><li><strong>阿里开源 Qwen3.8-Max</strong>：2.4 万亿参数旗舰首次开源，编程能力直接对标 Claude 系列，程序员一句话就能让它从空文件夹写完整个项目。</li><li><strong>字节发布 SeedRealtime</strong>：原生音视频全双工大模型，豆包 App 已全量上线，”边看、边听、边说”不再是 PPT。</li><li><strong>DeepSeek V4-Pro 正式版进入倒计时</strong>：API 宣布大幅涨价，业界推测正式版即将发布，想省钱的抓紧。</li><li><strong>OpenAI 风波不断</strong>：GPT-6 被曝 8 月强行发布，同时因 Astra 模型”自主攻防能力过强”暂停部分研发。</li><li><strong>全国产 10 万卡超集群”曙光8000”投用</strong>：国产算力基建里程碑，AI 训练不再看美国脸色。</li></ol><hr><h2 id="重点深度（值得展开的-2-条）"><a href="#重点深度（值得展开的-2-条）" class="headerlink" title="重点深度（值得展开的 2 条）"></a>重点深度（值得展开的 2 条）</h2><h3 id="一、Qwen3-8-Max：国产开源模型的新王座"><a href="#一、Qwen3-8-Max：国产开源模型的新王座" class="headerlink" title="一、Qwen3.8-Max：国产开源模型的新王座"></a>一、Qwen3.8-Max：国产开源模型的新王座</h3><p><strong>一句话</strong>：这是千问系列史上最大、最强的模型，也是首个对外开源的 Max 级别旗舰——总参数 <strong>2.4 万亿</strong>，单次激活约 <strong>950 亿参数</strong>，支持 <strong>100 万 Token 上下文</strong>，原生集成多模态视觉理解。</p><p><strong>为什么值得关注？</strong></p><ul><li><strong>编程能力登顶开源阵营</strong>：在 Frontend Code Arena 排行榜位列第四（1668 分），仅次于 Claude Opus 5 (Max) 的 1705 分和 Kimi K3 (Max) 的 1676 分。</li><li><strong>自主编程新突破</strong>：官方演示中，程序员只需一句话指令，模型可从空文件夹出发独立完成真实项目交付，连续自主工作数天几乎不需要人插手。</li><li><strong>“两万亿俱乐部”第二人</strong>：继 Kimi K3（2.8 万亿）之后，Qwen3.8-Max（2.4 万亿）成为国产大模型第二位成员。开源阵营对闭源模型发起新一轮冲击。</li></ul><p><strong>对普通用户意味着什么？</strong></p><ul><li>API 已上线千问 AI 平台，下周权重正式开源——这意味着你可以<strong>免费部署一个 2.4 万亿参数的编程助手</strong>（如果你的显卡扛得住）。</li><li>对个人开发者来说，Qwen3.8-Max 的办公 Agent 能力（Cowork）值得一试：写周报、做 PPT、整理数据，一条龙。</li></ul><blockquote><p>💡 <strong>怎么用起来</strong>：打开 <a href="https://tongyi.aliyun.com/">千问 AI 平台</a> 就能直接用 Max 模型；开发者等下周开源后可用 <a href="https://ollama.com/">Ollama</a> 或 vLLM 本地部署。想了解部署细节，先看我们的 <a href="/2026/07/11/%E5%BC%80%E6%BA%90%E5%A4%A7%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E4%B8%8B%E8%BD%BD%E5%88%B0API%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">开源大模型部署指南</a>。</p></blockquote><h3 id="二、字节-SeedRealtime：音视频实时对话，豆包先上了"><a href="#二、字节-SeedRealtime：音视频实时对话，豆包先上了" class="headerlink" title="二、字节 SeedRealtime：音视频实时对话，豆包先上了"></a>二、字节 SeedRealtime：音视频实时对话，豆包先上了</h3><p><strong>一句话</strong>：字节跳动 8 月 5 日发布原生音视频全双工大模型 SeedRealtime，用统一架构原生融合音频、视频与文本，在连续多模态信息流上实时交互——“边看、边听、边说”。</p><p><strong>为什么值得关注？</strong></p><ul><li><strong>原生全双工</strong>：不是”语音识别 + 文本回复 + 语音合成”的拼接，而是端到端统一架构，对话节奏问题比级联模型减少一半，单次对话完整顺畅交流概率显著提升。</li><li><strong>已经能用</strong>：SeedRealtime 已在豆包 App 全量上线，更新到最新版本即可体验，不是发布会 PPT。</li></ul><p><strong>普通用户怎么玩？</strong></p><ul><li>打开豆包 App，试试对着摄像头问它”我这盆绿萝是不是该浇水了”——它能边看边说。</li><li>这是 AI 从”打字聊天”走向”真人对话”的关键一步，未来客服、教学、陪伴场景都会变。</li></ul><blockquote><p>💡 <strong>延伸阅读</strong>：想理解多模态模型背后的原理，可看我们的 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a>。</p></blockquote><hr><h2 id="工具上新（值得试的）"><a href="#工具上新（值得试的）" class="headerlink" title="工具上新（值得试的）"></a>工具上新（值得试的）</h2><table><thead><tr><th>工具&#x2F;模型</th><th>一句话点评</th><th>上手难度</th></tr></thead><tbody><tr><td><strong>Qwen3.8-Max</strong>（阿里）</td><td>2.4T 参数编程旗舰，下周开源</td><td>⭐⭐</td></tr><tr><td><strong>SeedRealtime</strong>（字节）</td><td>豆包 App 直接体验音视频对话</td><td>⭐</td></tr><tr><td><strong>Hy ASR 3.0 preview</strong>（腾讯混元）</td><td>新一代语音识别，元宝免费开放</td><td>⭐</td></tr><tr><td><strong>Pokee-Isaac 28B</strong>（Pokee AI）</td><td>1000 万 Token 上下文的 Agent 模型，RULER@10M 93.3%</td><td>⭐⭐⭐</td></tr><tr><td><strong>MedBench 5.0</strong>（上海AI实验室）</td><td>钟南山等院士共建的医疗大模型评测基准</td><td>⭐⭐⭐</td></tr></tbody></table><hr><h2 id="避坑提醒"><a href="#避坑提醒" class="headerlink" title="避坑提醒"></a>避坑提醒</h2><ol><li><strong>DeepSeek API 要涨价</strong>：V4 系列高峰时段百万 Token 输入从 3 元涨到 6 元，输出从 6 元涨到 12 元。日常高频调用前先评估成本，或转用 V4-Flash 轻量版。</li><li><strong>GPT-6 传闻别全信</strong>：X 平台爆料”8 月强行发布”目前是自媒体消息，官方未确认。警惕借此炒币、卖课的。</li><li><strong>“自主攻防能力过强”是双刃剑</strong>：OpenAI 暂停 Astra 模型部分研发说明 AI 安全不是玩笑。用 AI 写代码时，涉及生产环境的指令务必人工 review。</li></ol><hr><h2 id="学习建议"><a href="#学习建议" class="headerlink" title="学习建议"></a>学习建议</h2><ul><li>想真正看懂这些大模型：先读 <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a>，再读 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a>。</li><li>想动手跑模型：WebGPU 直接在浏览器跑，<a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B%EF%BC%88%E9%9B%B6%E6%88%90%E6%9C%AC%E6%9C%AC%E5%9C%B0%E6%8E%A8%E7%90%86%EF%BC%89/">零成本本地推理实战</a>，不用买显卡。</li><li>想选对模型：看 [国产大模型横评：DeepSeek &#x2F; Kimi &#x2F; Qwen &#x2F; GLM 谁更值得用？](&#x2F;2026&#x2F;08&#x2F;06&#x2F;国产大模型横评：DeepSeek Kimi Qwen GLM 谁更值得用？&#x2F;)。</li></ul><hr><h2 id="下期预告"><a href="#下期预告" class="headerlink" title="下期预告"></a>下期预告</h2><p>AI 双周速递·第三期将重点关注：<strong>DeepSeek V4-Pro 正式版</strong>（预计 8 月初发布，届时第一时间实测）、<strong>Qwen3.8-Max 开源后的本地部署体验</strong>，以及 8 月下旬可能出现的更多新应用。关注我们，不错过每一次重要更新。</p><blockquote><p><strong>追踪 AGI 新应用，探寻 AI 真善美。</strong> 觉得有用，欢迎在评论区聊聊你最想了解哪个 AI 工具，我们下期安排！</p></blockquote>]]>
    </content>
    <id>https://aijvs.com/2026/08/12/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E7%AC%AC%E4%BA%8C%E6%9C%9F%EF%BC%9AQwen3.8-Max%20%E5%BC%80%E6%BA%90%E7%82%B8%E5%9C%BA%EF%BC%8C%E5%AD%97%E8%8A%82%20SeedRealtime%20%E8%BE%B9%E7%9C%8B%E8%BE%B9%E8%81%8A/</id>
    <link href="https://aijvs.com/2026/08/12/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E7%AC%AC%E4%BA%8C%E6%9C%9F%EF%BC%9AQwen3.8-Max%20%E5%BC%80%E6%BA%90%E7%82%B8%E5%9C%BA%EF%BC%8C%E5%AD%97%E8%8A%82%20SeedRealtime%20%E8%BE%B9%E7%9C%8B%E8%BE%B9%E8%81%8A/"/>
    <published>2026-08-12T14:30:00.000Z</published>
    <summary>追踪AGI新应用，探寻AI真善美。第二期速递盘点：阿里Qwen3.8-Max 2.4万亿参数首次开源、字节SeedRealtime音视频实时对话上线、DeepSeek V4-Pro涨价倒计时、OpenAI GPT-6风波。带你快速掌握8月上半月AI圈最重要的事。</summary>
    <title>AI双周速递·第二期：Qwen3.8-Max 开源炸场，字节 SeedRealtime 边看边聊</title>
    <updated>2026-08-12T14:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="前沿资讯" scheme="https://aijvs.com/categories/%E5%89%8D%E6%B2%BF%E8%B5%84%E8%AE%AF/"/>
    <category term="大模型" scheme="https://aijvs.com/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="DeepSeek" scheme="https://aijvs.com/tags/DeepSeek/"/>
    <category term="评测" scheme="https://aijvs.com/tags/%E8%AF%84%E6%B5%8B/"/>
    <category term="Kimi" scheme="https://aijvs.com/tags/Kimi/"/>
    <category term="Qwen" scheme="https://aijvs.com/tags/Qwen/"/>
    <category term="GLM" scheme="https://aijvs.com/tags/GLM/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本篇是 P3 前沿系列的收官篇。建议先读 <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> 和 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a>，理解”参数&#x2F;上下文&#x2F;量化”这些词再来看选型，事半功倍。</p></blockquote><hr><h2 id="2026-年-8-月，国产大模型的”神仙打架”"><a href="#2026-年-8-月，国产大模型的”神仙打架”" class="headerlink" title="2026 年 8 月，国产大模型的”神仙打架”"></a>2026 年 8 月，国产大模型的”神仙打架”</h2><p>一个月内，三家头部厂商接连放大招：</p><ul><li><strong>7&#x2F;16</strong>：Kimi K3 发布（2.8 万亿参数，全球最大开源模型）</li><li><strong>7&#x2F;19</strong>：Qwen 3.8-Max 预览版上线（2.4 万亿参数，开源回归）</li><li><strong>7&#x2F;31</strong>：DeepSeek V4-Flash 正式版 API 公测</li><li><strong>8&#x2F;3</strong>：GLM-5.3 意外泄露（尚未正式发布）</li></ul><p>四家神仙打架，我们怎么选？本篇用一张表 + 场景拆解，帮你做决定。</p><blockquote><p>全部数据来自公开报道与基准测试（标注置信度）。AI 领域变化极快，以官方公告为准。</p></blockquote><hr><h2 id="一、四大家族对比总表"><a href="#一、四大家族对比总表" class="headerlink" title="一、四大家族对比总表"></a>一、四大家族对比总表</h2><table><thead><tr><th>维度</th><th>DeepSeek V4-Flash</th><th>Kimi K3</th><th>Qwen 3.8-Max</th><th>GLM-5</th></tr></thead><tbody><tr><td><strong>厂商</strong></td><td>深度求索</td><td>月之暗面</td><td>阿里</td><td>智谱</td></tr><tr><td><strong>总参数</strong></td><td>130亿激活（未公开总量）</td><td><strong>2.8万亿</strong></td><td>2.4万亿</td><td>7440亿</td></tr><tr><td><strong>激活参数</strong></td><td>130亿</td><td>约1040亿</td><td>未公开</td><td>400亿</td></tr><tr><td><strong>架构</strong></td><td>MoE</td><td>MoE（896专家&#x2F;激活16）</td><td>MoE</td><td>MoE（slime RL）</td></tr><tr><td><strong>上下文</strong></td><td>长上下文</td><td><strong>100万token</strong></td><td>128K+</td><td>200K</td></tr><tr><td><strong>开源</strong></td><td>API</td><td>✅完整权重</td><td>承诺开源</td><td>部分</td></tr><tr><td><strong>编程能力</strong></td><td>WebDev 1577分</td><td><strong>Frontend Code Arena 1679分（第1）</strong></td><td>编程国产第1</td><td>日常编码强</td></tr><tr><td><strong>性价比</strong></td><td><strong>98%缓存命中，极致</strong></td><td>中</td><td>高</td><td><strong>100万token仅$3.2-4.6</strong></td></tr><tr><td><strong>发布时间</strong></td><td>2026-07-31</td><td>2026-07-16&#x2F;27</td><td>2026-07-19</td><td>2026-06</td></tr><tr><td><strong>适合场景</strong></td><td>高频API调用、Agent</td><td>长上下文、复杂推理、研究</td><td>编程、全模态、生态</td><td>长时后台任务、低成本</td></tr></tbody></table><p><strong>置信度</strong>：参数&#x2F;时间线为高（多源一致）；基准分数为中高（不同榜单口径不同）。</p><hr><h2 id="二、逐家拆解：谁适合你？"><a href="#二、逐家拆解：谁适合你？" class="headerlink" title="二、逐家拆解：谁适合你？"></a>二、逐家拆解：谁适合你？</h2><h3 id="🥇-Kimi-K3：长文本之王-研究者的宝藏"><a href="#🥇-Kimi-K3：长文本之王-研究者的宝藏" class="headerlink" title="🥇 Kimi K3：长文本之王 + 研究者的宝藏"></a>🥇 Kimi K3：长文本之王 + 研究者的宝藏</h3><p><strong>适合谁</strong>：处理超长文档、做研究、想私有化部署的人。</p><ul><li><strong>100 万 token 上下文</strong>：单次可处理约 75 万单词——整本《三体》三部曲都能塞进去</li><li><strong>全球最大开源模型</strong>：完整权重开放，配合 <a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/">WebGPU实战</a> 或本地部署，数据完全私有</li><li><strong>代码榜第一</strong>：Frontend Code Arena 1679 分，超越 Claude Fable 5</li></ul><p><strong>注意</strong>：模型巨大，本地跑需要多卡集群（适合有算力的人）；普通用户走 API。</p><h3 id="🥇-DeepSeek-V4-Flash：性价比之王-Agent-首选"><a href="#🥇-DeepSeek-V4-Flash：性价比之王-Agent-首选" class="headerlink" title="🥇 DeepSeek V4-Flash：性价比之王 + Agent 首选"></a>🥇 DeepSeek V4-Flash：性价比之王 + Agent 首选</h3><p><strong>适合谁</strong>：开发者、高频调用 API、做 AI 应用。</p><ul><li><strong>98% 缓存命中</strong>：同样的功能，成本可能是别人的 1&#x2F;10</li><li><strong>Agent 能力大幅增强</strong>：<a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">LLM 原理</a> 里说的”推理时扩展”，它就是标杆</li><li><strong>原生 Responses API</strong>：开发者接入零成本（特别是用 Codex 生态的）</li><li>130 亿激活参数”以下克上”——小身材大能量</li></ul><h3 id="🥇-Qwen-3-8-Max：全模态生态-编程新王"><a href="#🥇-Qwen-3-8-Max：全模态生态-编程新王" class="headerlink" title="🥇 Qwen 3.8-Max：全模态生态 + 编程新王"></a>🥇 Qwen 3.8-Max：全模态生态 + 编程新王</h3><p><strong>适合谁</strong>：需要视觉&#x2F;语音&#x2F;文本多模态、阿里云生态用户。</p><ul><li><strong>编程能力国产第一</strong>（Arena 编程子榜中国第一）</li><li><strong>2.4 万亿参数回归开源</strong>：阿里旗舰线首次开源（闭源两代后）</li><li><strong>全模态</strong>：文本、图像、视频统一理解（<a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> 里讲的混合注意力架构）</li><li>阿里云百炼平台成熟，企业级服务完善</li></ul><h3 id="🥇-GLM-5：后台任务长跑冠军"><a href="#🥇-GLM-5：后台任务长跑冠军" class="headerlink" title="🥇 GLM-5：后台任务长跑冠军"></a>🥇 GLM-5：后台任务长跑冠军</h3><p><strong>适合谁</strong>：长时后台任务、批量处理、预算敏感团队。</p><ul><li><strong>单次 100 万 token 仅 $3.2-4.6</strong>：四家中最低价</li><li><strong>slime RL 框架</strong>：强化学习驱动的 MoE，日常编码稳定</li><li><strong>200K 上下文</strong>：长时后台任务（定时摘要、数据清洗）的利器</li><li>GLM-5.3 泄露在即（8&#x2F;3），值得关注升级版</li></ul><hr><h2 id="三、场景选型速查表"><a href="#三、场景选型速查表" class="headerlink" title="三、场景选型速查表"></a>三、场景选型速查表</h2><table><thead><tr><th>你的需求</th><th>推荐</th><th>理由</th></tr></thead><tbody><tr><td>聊天&#x2F;写作&#x2F;翻译</td><td>DeepSeek V4-Flash</td><td>便宜大碗</td></tr><tr><td>处理整本书&#x2F;超长合同</td><td>Kimi K3</td><td>100万上下文碾压</td></tr><tr><td>写代码</td><td>Qwen 3.8-Max &#x2F; Kimi K3</td><td>两个编程王者</td></tr><tr><td>做 AI 应用（API）</td><td>DeepSeek V4-Flash</td><td>98%缓存命中省成本</td></tr><tr><td>私有化部署</td><td>Kimi K3 &#x2F; Qwen</td><td>开源权重</td></tr><tr><td>批量后台任务</td><td>GLM-5</td><td>每百万token最便宜</td></tr><tr><td>多模态（图文视频）</td><td>Qwen 3.8-Max</td><td>全模态旗舰</td></tr><tr><td>学习原理&#x2F;研究</td><td>Kimi K3（读技术报告）</td><td>架构最前沿</td></tr></tbody></table><hr><h2 id="四、学习者视角：这些模型对我们的意义"><a href="#四、学习者视角：这些模型对我们的意义" class="headerlink" title="四、学习者视角：这些模型对我们的意义"></a>四、学习者视角：这些模型对我们的意义</h2><h3 id="1-学习资源"><a href="#1-学习资源" class="headerlink" title="1. 学习资源"></a>1. 学习资源</h3><ul><li><strong>Kimi K3 开源三件套</strong>（MoonEP 训练框架、FlashKDA 注意力算子、AgentEnv 沙箱）——是 <a href="/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/">开源项目贡献指南</a> 提到的顶级学习素材</li><li><strong>DeepSeek V4 技术报告</strong>——理解”低成本高性能”如何做到的教科书</li></ul><h3 id="2-实践建议"><a href="#2-实践建议" class="headerlink" title="2. 实践建议"></a>2. 实践建议</h3><ul><li>先看 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a> 理解架构，再动手</li><li>想不花钱玩模型？<a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/">WebGPU实战</a> 让浏览器跑 Qwen2.5 小模型</li><li>想跑本地大模型？<a href="/course/">RAG 实战</a>（课程中心路线 B 进阶阶段）</li></ul><h3 id="3-就业信号"><a href="#3-就业信号" class="headerlink" title="3. 就业信号"></a>3. 就业信号</h3><p>四家厂商的竞争焦点从”参数竞赛”转向”<strong>应用 + 生态 + 成本</strong>“——这意味 AI 应用开发者的黄金时代。方向 C 的 <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递</a> 会持续追踪这个趋势。</p><hr><h2 id="五、P3-系列收官：一张图回顾我们学了什么"><a href="#五、P3-系列收官：一张图回顾我们学了什么" class="headerlink" title="五、P3 系列收官：一张图回顾我们学了什么"></a>五、P3 系列收官：一张图回顾我们学了什么</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">P3-1  AI双周速递创刊号      → 看见趋势（Kimi K3 / DeepSeek V4 / WAIC）</span><br><span class="line">  ↓</span><br><span class="line">P3-2  Transformer深度解读    → 理解底座（注意力 / MoE / 位置编码）</span><br><span class="line">  ↓</span><br><span class="line">P3-3  大语言模型原理         → 看懂训练（预训练 / SFT / RLHF / KV Cache）</span><br><span class="line">  ↓</span><br><span class="line">P3-4  WebGPU实战            → 动手落地（浏览器跑模型，零成本）</span><br><span class="line">  ↓</span><br><span class="line">P3-5  顶会论文解读           → 触摸前沿（ICML 2026 / CaRE / 注意力进化）</span><br><span class="line">  ↓</span><br><span class="line">P3-6  国产大模型横评（本篇）  → 做出选择（四大家怎么选）</span><br></pre></td></tr></table></figure><p><strong>从”看见新闻”到”理解原理”到”动手实践”到”做出决策”</strong>——这就是 AIJVS 想带你走完的路。</p><h3 id="下一步：P3-之后"><a href="#下一步：P3-之后" class="headerlink" title="下一步：P3 之后"></a>下一步：P3 之后</h3><ul><li><strong>方向 A 项目式</strong>：RAG 知识库实战（Docker + Ollama + Milvus）、LlamaFactory 微调你的模型</li><li><strong>方向 B 评测</strong>：中文 Embedding 排行榜、国产 AI 编程助手盲测</li><li><strong>方向 C 周刊</strong>：AI 双周速递第二期（DeepSeek V4-Pro 预计 8 月初发布，敬请期待）</li></ul><p>全部内容都会与 <a href="/course/">课程中心</a> 的路线 A&#x2F;B 打通，互相引用、层层递进。</p><hr><h2 id="六、最终建议（写在最后）"><a href="#六、最终建议（写在最后）" class="headerlink" title="六、最终建议（写在最后）"></a>六、最终建议（写在最后）</h2><p><strong>不要纠结”哪个模型最强”——要问”哪个模型最适合我的场景”。</strong></p><ul><li>预算有限 → DeepSeek V4-Flash</li><li>长文档 → Kimi K3</li><li>编程 → Qwen &#x2F; Kimi</li><li>私有化 → Kimi K3 &#x2F; Qwen 开源版</li><li>批量任务 → GLM</li></ul><p><strong>动手才是最好的学习</strong>。打开 <a href="/course/">课程中心快速通道</a>，今天就开始你的第一个 AI 项目。</p><blockquote><p>下一篇速递（8月中下旬），我们会实测 DeepSeek V4-Pro 和 GLM-5.3，用数据说话。如果你有想测的场景，评论区告诉我——我们下一期见！</p></blockquote><hr><p><strong>互动</strong>：你现在在用哪家模型？踩过什么坑？评论区分享，帮助更多初学者避坑。</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/%E5%9B%BD%E4%BA%A7%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%A8%AA%E8%AF%84%EF%BC%9ADeepSeek%20Kimi%20Qwen%20GLM%20%E8%B0%81%E6%9B%B4%E5%80%BC%E5%BE%97%E7%94%A8%EF%BC%9F/</id>
    <link href="https://aijvs.com/2026/08/06/%E5%9B%BD%E4%BA%A7%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%A8%AA%E8%AF%84%EF%BC%9ADeepSeek%20Kimi%20Qwen%20GLM%20%E8%B0%81%E6%9B%B4%E5%80%BC%E5%BE%97%E7%94%A8%EF%BC%9F/"/>
    <published>2026-08-06T07:00:00.000Z</published>
    <summary>2026年8月国产大模型全对比：Kimi K3、DeepSeek V4-Flash、Qwen 3.8-Max、GLM-5系列。参数、价格、场景、上手建议全解析，帮你选对模型、省下真金白银。</summary>
    <title>国产大模型横评：DeepSeek / Kimi / Qwen / GLM 谁更值得用？</title>
    <updated>2026-08-06T07:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="前沿资讯" scheme="https://aijvs.com/categories/%E5%89%8D%E6%B2%BF%E8%B5%84%E8%AE%AF/"/>
    <category term="大模型" scheme="https://aijvs.com/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="进阶" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6/"/>
    <category term="论文解读" scheme="https://aijvs.com/tags/%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/"/>
    <category term="ICML" scheme="https://aijvs.com/tags/ICML/"/>
    <category term="持续学习" scheme="https://aijvs.com/tags/%E6%8C%81%E7%BB%AD%E5%AD%A6%E4%B9%A0/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本篇是 P3 前沿系列的论文解读篇，建议先看 <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> 掌握基础概念。</p></blockquote><hr><h2 id="为什么读论文？一个被低估的能力"><a href="#为什么读论文？一个被低估的能力" class="headerlink" title="为什么读论文？一个被低估的能力"></a>为什么读论文？一个被低估的能力</h2><p>在 <a href="/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/">开源项目贡献指南</a> 里我们说过，参与开源社区的第一步是”读代码”。而<strong>读论文</strong>，是理解 AI 前沿的唯一方式——因为：</p><ol><li><strong>新闻滞后</strong>：等你从新闻看到某个技术，它已经是半年前的研究了</li><li><strong>博客稀释</strong>：二手解读常丢失关键细节</li><li><strong>论文是源头</strong>：所有模型（Kimi K3、DeepSeek V4）的技术报告，本质都是论文</li></ol><p><strong>好消息</strong>：读论文不需要数学博士。本篇用大白话拆解 2026 年最重要的几篇，并教你一套”5 分钟读懂一篇论文”的方法。</p><hr><h2 id="一、ICML-2026-概况"><a href="#一、ICML-2026-概况" class="headerlink" title="一、ICML 2026 概况"></a>一、ICML 2026 概况</h2><p><strong>ICML</strong>（国际机器学习大会）是机器学习领域最顶级的学术会议。第 43 届 ICML 2026 于 7 月 6 日开幕。</p><h3 id="本届亮点（置信度：高）"><a href="#本届亮点（置信度：高）" class="headerlink" title="本届亮点（置信度：高）"></a>本届亮点（置信度：高）</h3><ul><li><strong>清华团队获最佳论文奖</strong>——中国学者在顶会的存在感持续上升</li><li><strong>DeepMind 经典之作拿下时间检验奖</strong>——十年前的工作影响至今</li><li><strong>三大趋势</strong>（会议官方总结）：<ol><li><strong>新推理模式的模型架构</strong>（如混合注意力、状态空间模型）</li><li><strong>更可靠的智能体（Agent）</strong>（长期任务执行、自我纠错）</li><li><strong>降低训练与推理成本的基础设施</strong>（量化、稀疏化、高效并行）</li></ol></li></ul><blockquote><p>这三条趋势，正好和我们的 <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a> 完全对上：Kimi K3 的 MoE 是”低成本架构”，DeepSeek V4-Flash 的 Agent 能力增强是”更可靠的智能体”——<strong>学术和产业在同一方向上共振</strong>。</p></blockquote><hr><h2 id="二、重点论文-1：港大-CaRE——让-AI-持续学习不遗忘"><a href="#二、重点论文-1：港大-CaRE——让-AI-持续学习不遗忘" class="headerlink" title="二、重点论文 1：港大 CaRE——让 AI 持续学习不遗忘"></a>二、重点论文 1：港大 CaRE——让 AI 持续学习不遗忘</h2><h3 id="2-1-它解决什么问题？"><a href="#2-1-它解决什么问题？" class="headerlink" title="2.1 它解决什么问题？"></a>2.1 它解决什么问题？</h3><p><strong>灾难性遗忘（Catastrophic Forgetting）</strong>：神经网络学新东西时会”忘掉”旧知识。就像一个人学完法语忘了英语。</p><p>传统持续学习（Continual Learning）方法，最多能处理几十个任务。而现实世界的 AI 需要<strong>终身学习</strong>——今天学写代码、明天学画图、后天学开车，不能学一个忘一个。</p><h3 id="2-2-CaRE-怎么做的？"><a href="#2-2-CaRE-怎么做的？" class="headerlink" title="2.2 CaRE 怎么做的？"></a>2.2 CaRE 怎么做的？</h3><p><strong>CaRE（Scalable Continual Learner with efficient Bi-Level Routing Mixture-of-Experts）</strong>，来自香港大学团队，ICML 2026。</p><p>核心创新：</p><ol><li><strong>双层路由 MoE</strong>：把专家网络分成两层，上层路由选择”任务群”，下层路由选择”具体专家”。新任务来了，只新增专家，不动旧专家——<strong>旧知识不被覆盖，新知识有地方放</strong></li><li><strong>首次扩展到 300+ 任务</strong>：在超长任务序列上大幅超越现有基线</li><li><strong>开源</strong>：代码和数据（OmniBenchmark-1K 评测集）全部公开</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">新任务输入 → 上层路由(选任务群) → 下层路由(选专家) → 只更新新专家 → 旧专家冻结</span><br></pre></td></tr></table></figure><h3 id="2-3-和-MoE-的关系"><a href="#2-3-和-MoE-的关系" class="headerlink" title="2.3 和 MoE 的关系"></a>2.3 和 MoE 的关系</h3><p>还记得 <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> 里 Kimi K3 的 896 个专家吗？CaRE 是 <strong>MoE 在”持续学习”场景的应用</strong>——同一个架构思想，不同的用途：</p><table><thead><tr><th>场景</th><th>MoE 用途</th></tr></thead><tbody><tr><td>Kimi K3 推理</td><td>每 token 只激活 16 专家 → 省算力</td></tr><tr><td>CaRE 持续学习</td><td>新任务只动新专家 → 不遗忘</td></tr></tbody></table><p><strong>这就是读论文的乐趣：看到同一思想在不同场景的开花结果。</strong></p><hr><h2 id="三、重点论文-2：CVPR-2026-UCAN——注意力机制的进化"><a href="#三、重点论文-2：CVPR-2026-UCAN——注意力机制的进化" class="headerlink" title="三、重点论文 2：CVPR 2026 UCAN——注意力机制的进化"></a>三、重点论文 2：CVPR 2026 UCAN——注意力机制的进化</h2><p>虽然本篇聚焦 ICML，但 CVPR 2026 的注意力机制论文同样精彩，而且和我们的 <a href="/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/">计算机视觉入门</a> 直接相关。</p><h3 id="UCAN：轻量级超分网络的注意力革新"><a href="#UCAN：轻量级超分网络的注意力革新" class="headerlink" title="UCAN：轻量级超分网络的注意力革新"></a>UCAN：轻量级超分网络的注意力革新</h3><p><strong>UCAN（Unified Convolutional Attention Network）</strong> 提出三种注意力机制的组合：</p><ol><li><strong>Flash Attention</strong>：高效大窗口注意力（计算速度快）</li><li><strong>Hedgehog Attention</strong>：新提出的线性注意力变体，解决传统线性注意力的”秩坍塌”（信息丢失）问题</li><li><strong>混合注意力</strong>：局部依赖（卷积）+ 全局依赖（注意力）融合</li></ol><p><strong>核心贡献</strong>：用更少的计算量，实现了更大感受野的图像超分（把模糊图变清晰）。图像超分是手机摄影、医学影像的关键技术。</p><blockquote><p>这印证了 ICML 2026 的趋势一：”新推理模式的模型架构”——2026 年，注意力机制的创新不再是”堆参数”，而是”用更聪明的结构换效率”。</p></blockquote><hr><h2 id="四、重点论文-3：VLLM-视觉-Token-剪枝研究"><a href="#四、重点论文-3：VLLM-视觉-Token-剪枝研究" class="headerlink" title="四、重点论文 3：VLLM 视觉 Token 剪枝研究"></a>四、重点论文 3：VLLM 视觉 Token 剪枝研究</h2><p><strong>《When Token Pruning is Worse than Random》</strong>（CVPR 2026）：</p><p>这篇论文提出了”信息视界”（Information Horizon）概念，发现<strong>视觉大模型（VLLM）中，视觉信息在网络深处会均匀消失</strong>——超过某一层后，视觉 token 的信息量趋近于零。</p><p><strong>实际意义</strong>：</p><ul><li>现有视觉 token 剪枝方法在某些层会失效（效果还不如随机剪枝）</li><li>为多模态大模型的效率优化提供了理论指导</li><li>直接影响 <a href="/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%EF%BC%88CIFAR-10%EF%BC%89/">图像分类（CIFAR-10）</a> 这类任务的多模态扩展</li></ul><hr><h2 id="五、方法：5-分钟读懂一篇论文"><a href="#五、方法：5-分钟读懂一篇论文" class="headerlink" title="五、方法：5 分钟读懂一篇论文"></a>五、方法：5 分钟读懂一篇论文</h2><p>这是本篇文章最有价值的部分——<strong>一套可复用的论文阅读法</strong>：</p><h3 id="第一步：看标题-摘要（30秒）"><a href="#第一步：看标题-摘要（30秒）" class="headerlink" title="第一步：看标题+摘要（30秒）"></a>第一步：看标题+摘要（30秒）</h3><p>回答三个问题：</p><ol><li>它解决了什么问题？</li><li>它用什么方法？</li><li>效果比谁好多少？</li></ol><h3 id="第二步：看图（2分钟）"><a href="#第二步：看图（2分钟）" class="headerlink" title="第二步：看图（2分钟）"></a>第二步：看图（2分钟）</h3><p>论文的图表浓缩了 80% 的信息。重点看：</p><ul><li>架构图：系统长什么样</li><li>实验表格：比基线好多少</li><li>可视化：为什么有效</li></ul><h3 id="第三步：看结论-Related-Work（1分钟）"><a href="#第三步：看结论-Related-Work（1分钟）" class="headerlink" title="第三步：看结论+Related Work（1分钟）"></a>第三步：看结论+Related Work（1分钟）</h3><ul><li>结论：作者认为贡献是什么</li><li>Related Work：这篇论文站在谁的肩膀上（追踪引用链）</li></ul><h3 id="第四步：决定是否精读"><a href="#第四步：决定是否精读" class="headerlink" title="第四步：决定是否精读"></a>第四步：决定是否精读</h3><ul><li>与你研究相关 → 精读方法部分</li><li>只是了解 → 到此为止</li></ul><h3 id="工具推荐"><a href="#工具推荐" class="headerlink" title="工具推荐"></a>工具推荐</h3><ul><li><strong>arXiv</strong>：论文源仓库（记得看 <a href="/nav/">AI导航</a> 里的学术工具）</li><li><strong>Hugging Face Papers</strong>：带讨论区的论文解读</li><li><strong>Semantic Scholar</strong>：引用追踪神器</li></ul><hr><h2 id="六、总结与联动"><a href="#六、总结与联动" class="headerlink" title="六、总结与联动"></a>六、总结与联动</h2><h3 id="核心记忆点"><a href="#核心记忆点" class="headerlink" title="核心记忆点"></a>核心记忆点</h3><ol><li>ICML 2026 三大趋势：新架构、可靠 Agent、低成本</li><li>港大 CaRE：双层路由 MoE 破解灾难性遗忘，首次 300+ 任务</li><li>注意力机制 2026 主旋律是”效率”而非”规模”</li><li>读论文四步法：摘要→图→结论→精读</li></ol><h3 id="联动路径"><a href="#联动路径" class="headerlink" title="联动路径"></a>联动路径</h3><ul><li>理论基础：<a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> → <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a></li><li>实战延伸：<a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/">WebGPU实战：在浏览器里跑大模型</a>（论文方法 → 实际应用）</li><li>最新动态：<a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a></li><li>参与研究：<a href="/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/">开源项目贡献指南</a></li></ul><h3 id="下篇预告"><a href="#下篇预告" class="headerlink" title="下篇预告"></a>下篇预告</h3><p>下一篇 <a href="/2026/08/06/%E5%9B%BD%E4%BA%A7%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%A8%AA%E8%AF%84%EF%BC%9ADeepSeek%20Kimi%20Qwen%20GLM%20%E8%B0%81%E6%9B%B4%E5%80%BC%E5%BE%97%E7%94%A8%EF%BC%9F/">国产大模型横评：DeepSeek &#x2F; Kimi &#x2F; Qwen &#x2F; GLM 谁更值得用？</a>——把理论落到选型，P3 系列收官。</p><hr><p><strong>思考题</strong>：为什么说”灾难性遗忘”是通往通用人工智能（AGI）的必经之路？人类是怎么做到学新不忘旧的？（提示：睡眠、间隔重复、知识结构化——AI 都还没学会）。评论区见。</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/%E9%A1%B6%E4%BC%9A%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB%EF%BC%9AICML%202026%20%E4%B8%89%E5%A4%A7%E8%B6%8B%E5%8A%BF%E4%B8%8E%E6%B8%AF%E5%A4%A7%20CaRE%20%E6%8C%81%E7%BB%AD%E5%AD%A6%E4%B9%A0/</id>
    <link href="https://aijvs.com/2026/08/06/%E9%A1%B6%E4%BC%9A%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB%EF%BC%9AICML%202026%20%E4%B8%89%E5%A4%A7%E8%B6%8B%E5%8A%BF%E4%B8%8E%E6%B8%AF%E5%A4%A7%20CaRE%20%E6%8C%81%E7%BB%AD%E5%AD%A6%E4%B9%A0/"/>
    <published>2026-08-06T06:00:00.000Z</published>
    <summary>用大白话解读 ICML 2026 重点论文：清华团队最佳论文、港大 CaRE 破解300任务持续学习、注意力机制三趋势。带你掌握&quot;读懂AI论文&quot;的方法论。</summary>
    <title>顶会论文解读：ICML 2026 三大趋势与港大 CaRE 持续学习</title>
    <updated>2026-08-06T06:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="进阶" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6/"/>
    <category term="WebGPU" scheme="https://aijvs.com/tags/WebGPU/"/>
    <category term="浏览器" scheme="https://aijvs.com/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/"/>
    <category term="Transformers.js" scheme="https://aijvs.com/tags/Transformers-js/"/>
    <category term="部署" scheme="https://aijvs.com/tags/%E9%83%A8%E7%BD%B2/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本篇是 LLM 系列的实战篇。理论部分见 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a>。需要基础 HTML&#x2F;JavaScript 知识，Python 不是必需。</p></blockquote><hr><h2 id="为什么要在浏览器里跑-AI？"><a href="#为什么要在浏览器里跑-AI？" class="headerlink" title="为什么要在浏览器里跑 AI？"></a>为什么要在浏览器里跑 AI？</h2><p>先看一组真实数据（来自 2026 年 WebGPU 基准测试，Apple M4 Max + Chrome）：</p><table><thead><tr><th>指标</th><th>数值</th></tr></thead><tbody><tr><td>模型</td><td>Gemma-4-E2B（20 亿参数）</td></tr><tr><td>预填充速度</td><td><strong>4676 token&#x2F;秒</strong></td></tr><tr><td>解码速度</td><td>73.9 token&#x2F;秒</td></tr><tr><td>初始化时间</td><td>1.1 秒</td></tr><tr><td>模型大小</td><td>200 MB</td></tr><tr><td>GPU 内存</td><td>1.8 GB</td></tr></tbody></table><p><strong>你的浏览器，就是一台 AI 推理服务器。</strong> 这意味着：</p><ol><li><strong>零成本</strong>：不用买 GPU，不用租云服务器</li><li><strong>隐私安全</strong>：数据不出本地，聊天记录不会上传</li><li><strong>离线可用</strong>：模型加载后断网也能用</li><li><strong>无需安装</strong>：打开网页就是 AI 应用</li></ol><p>这正是 <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a> 里说的”AI 应用爆发”的一个缩影——当推理成本趋近于零，应用形态就被彻底改变。</p><hr><h2 id="一、WebGPU-是什么？"><a href="#一、WebGPU-是什么？" class="headerlink" title="一、WebGPU 是什么？"></a>一、WebGPU 是什么？</h2><p><strong>WebGPU</strong> 是浏览器的新一代 GPU 接口（类似 WebGL 的下一代，但更接近现代图形 API），2023 年起在 Chrome&#x2F;Edge&#x2F;Firefox 逐步可用，2026 年已全面普及。</p><p>关键点：</p><ul><li><strong>GPU 加速</strong>：利用显卡并行计算，比 CPU 快 10-100 倍</li><li><strong>AI 推理</strong>：虽然不是为 AI 设计的，但大模型的矩阵运算天然适合 GPU</li><li><strong>WASM 配合</strong>：WebAssembly 处理模型解析，WebGPU 负责计算</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">浏览器 → Transformers.js (推理引擎) → WebGPU (GPU加速) → 显卡</span><br></pre></td></tr></table></figure><hr><h2 id="二、Transformers-js：浏览器里的-HuggingFace"><a href="#二、Transformers-js：浏览器里的-HuggingFace" class="headerlink" title="二、Transformers.js：浏览器里的 HuggingFace"></a>二、Transformers.js：浏览器里的 HuggingFace</h2><p><strong>Transformers.js</strong>（HuggingFace 官方）把 Python 的 transformers 库搬到了 JavaScript。它支持：</p><ul><li><strong>数百个模型</strong>：Llama、Gemma、Phi、Qwen 等开源模型</li><li><strong>多任务</strong>：文本生成、分类、翻译、图像识别、语音识别</li><li><strong>自动选择后端</strong>：有 WebGPU 用 GPU，没有就退到 WASM&#x2F;CPU</li></ul><blockquote><p>小技巧：最新版需用 <code>npm i @huggingface/transformers</code>，或从 CDN 引入。</p></blockquote><hr><h2 id="三、实战：20-行代码跑文本生成"><a href="#三、实战：20-行代码跑文本生成" class="headerlink" title="三、实战：20 行代码跑文本生成"></a>三、实战：20 行代码跑文本生成</h2><h3 id="3-1-用-CDN（最简单，纯-HTML）"><a href="#3-1-用-CDN（最简单，纯-HTML）" class="headerlink" title="3.1 用 CDN（最简单，纯 HTML）"></a>3.1 用 CDN（最简单，纯 HTML）</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">title</span>&gt;</span>浏览器里的 AI<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h1</span>&gt;</span>🦄 浏览器本地大模型<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>首次加载需要下载模型（约200MB），之后可离线使用<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">textarea</span> <span class="attr">id</span>=<span class="string">&quot;input&quot;</span> <span class="attr">rows</span>=<span class="string">&quot;3&quot;</span> <span class="attr">cols</span>=<span class="string">&quot;60&quot;</span>&gt;</span>请用一句话介绍人工智能<span class="tag">&lt;/<span class="name">textarea</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button</span> <span class="attr">onclick</span>=<span class="string">&quot;run()&quot;</span>&gt;</span>生成<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">pre</span> <span class="attr">id</span>=<span class="string">&quot;output&quot;</span>&gt;</span>等待中...<span class="tag">&lt;/<span class="name">pre</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;module&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">import</span> &#123; pipeline &#125; <span class="keyword">from</span> <span class="string">&#x27;https://cdn.jsdelivr.net/npm/@huggingface/transformers@3&#x27;</span>;</span></span><br><span class="line"><span class="language-javascript">    </span></span><br><span class="line"><span class="language-javascript">    <span class="comment">// 创建文本生成流水线（device: &#x27;webgpu&#x27; 启用GPU加速）</span></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">const</span> generator = <span class="keyword">await</span> <span class="title function_">pipeline</span>(<span class="string">&#x27;text-generation&#x27;</span>, <span class="string">&#x27;onnx-community/Qwen2.5-0.5B-Instruct&#x27;</span>, &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="attr">device</span>: <span class="string">&#x27;webgpu&#x27;</span>,   <span class="comment">// 用 WebGPU 加速；不支持则去掉这行自动降级</span></span></span><br><span class="line"><span class="language-javascript">      <span class="attr">dtype</span>: <span class="string">&#x27;q4&#x27;</span>,        <span class="comment">// 4位量化，模型更小更快</span></span></span><br><span class="line"><span class="language-javascript">    &#125;);</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">run</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> text = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;input&#x27;</span>).<span class="property">value</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> output = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;output&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">      output.<span class="property">textContent</span> = <span class="string">&#x27;生成中...&#x27;</span>;</span></span><br><span class="line"><span class="language-javascript">      </span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> result = <span class="keyword">await</span> <span class="title function_">generator</span>(text, &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">max_new_tokens</span>: <span class="number">100</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">do_sample</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">temperature</span>: <span class="number">0.7</span>,</span></span><br><span class="line"><span class="language-javascript">      &#125;);</span></span><br><span class="line"><span class="language-javascript">      </span></span><br><span class="line"><span class="language-javascript">      output.<span class="property">textContent</span> = result[<span class="number">0</span>].<span class="property">generated_text</span>;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p><strong>保存为 <code>index.html</code>，双击打开</strong>（或 <code>npx serve</code>），等待模型下载即可使用。</p><h3 id="3-2-关键参数解读"><a href="#3-2-关键参数解读" class="headerlink" title="3.2 关键参数解读"></a>3.2 关键参数解读</h3><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td><code>device: &#39;webgpu&#39;</code></td><td>启用 GPU 加速，速度提升 10-100 倍</td></tr><tr><td><code>dtype: &#39;q4&#39;</code></td><td>4 位量化，200MB 模型只要 50MB</td></tr><tr><td><code>max_new_tokens</code></td><td>最多生成多少 token</td></tr><tr><td><code>temperature</code></td><td>随机性（0&#x3D;确定，1&#x3D;发散）</td></tr></tbody></table><h3 id="3-3-运行效果"><a href="#3-3-运行效果" class="headerlink" title="3.3 运行效果"></a>3.3 运行效果</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">输入: 请用一句话介绍人工智能</span><br><span class="line">输出: 人工智能是让计算机模拟人类智能行为的技术，</span><br><span class="line">      包括学习、推理、感知和自然语言处理等方面。</span><br></pre></td></tr></table></figure><p><strong>注意</strong>：首次运行会下载模型（浏览器缓存到本地），之后断网也能用。想换模型？把 <code>onnx-community/Qwen2.5-0.5B-Instruct</code> 换成任意支持的模型名（如 <code>Xenova/llama-3.2-1b</code>）即可。</p><hr><h2 id="四、进阶：做个本地-AI-助手页面"><a href="#四、进阶：做个本地-AI-助手页面" class="headerlink" title="四、进阶：做个本地 AI 助手页面"></a>四、进阶：做个本地 AI 助手页面</h2><p>把生成结果流式输出（像 ChatGPT 一样打字效果）：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 流式生成</span></span><br><span class="line"><span class="keyword">const</span> stream = <span class="keyword">await</span> <span class="title function_">generator</span>(text, &#123;</span><br><span class="line">  <span class="attr">max_new_tokens</span>: <span class="number">200</span>,</span><br><span class="line">  <span class="attr">stream</span>: <span class="literal">true</span>,          <span class="comment">// 开启流式</span></span><br><span class="line">  <span class="attr">callback_function</span>: <span class="function">(<span class="params">chunk</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> token = chunk[<span class="number">0</span>].<span class="property">output_token_text</span>;</span><br><span class="line">    output.<span class="property">textContent</span> += token;  <span class="comment">// 逐字追加显示</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>加上 CSS 聊天框样式，你就有了一个<strong>完全本地运行、数据不出设备</strong>的 AI 聊天助手——可以部署到 Cloudflare Pages &#x2F; Vercel &#x2F; GitHub Pages 上免费发布。</p><hr><h2 id="五、WebGPU-能跑多大模型？"><a href="#五、WebGPU-能跑多大模型？" class="headerlink" title="五、WebGPU 能跑多大模型？"></a>五、WebGPU 能跑多大模型？</h2><table><thead><tr><th>设备</th><th>可运行模型</th><th>说明</th></tr></thead><tbody><tr><td>手机（旗舰）</td><td>1-4B 量化</td><td>200MB-1GB</td></tr><tr><td>笔记本（集显）</td><td>4-8B 量化</td><td>1-3GB</td></tr><tr><td>台式机（独显）</td><td>8-32B 量化</td><td>3-10GB</td></tr><tr><td>工作站</td><td>70B 量化</td><td>需 40GB+ 显存</td></tr></tbody></table><blockquote><p>大规模模型（如 Kimi K3 的 2.8 万亿）不适合浏览器——但绝大多数日常场景（写作、翻译、摘要、代码补全），<strong>10B 以内的模型完全够用</strong>。这就是 <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">LLM 原理</a> 里说的”蒸馏 + 量化让模型变小变快”的落地。</p></blockquote><hr><h2 id="六、动手挑战（做完发评论区）"><a href="#六、动手挑战（做完发评论区）" class="headerlink" title="六、动手挑战（做完发评论区）"></a>六、动手挑战（做完发评论区）</h2><ol><li><strong>改造</strong>：把上面的代码加一个”加载进度条”（<code>generator</code> 支持 <code>progress_callback</code>）</li><li><strong>换模型</strong>：试试图像分类 <code>Xenova/vit-base-patch16-224</code>，用 WebGPU 识别本地图片</li><li><strong>发布</strong>：部署到 Cloudflare Pages，把链接发到评论区——让全世界用你的本地 AI</li></ol><h3 id="配套资源"><a href="#配套资源" class="headerlink" title="配套资源"></a>配套资源</h3><ul><li><a href="/nav/">AI导航</a> 里有 WebGPU 相关工具站（搜索 “WebGPU”）</li><li><a href="/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/">开源项目贡献指南</a> 教你如何给 Transformers.js 提 PR</li></ul><hr><h2 id="七、总结"><a href="#七、总结" class="headerlink" title="七、总结"></a>七、总结</h2><table><thead><tr><th>知识点</th><th>一句话</th></tr></thead><tbody><tr><td>WebGPU</td><td>浏览器 GPU 接口，让 AI 推理本地化</td></tr><tr><td>Transformers.js</td><td>HuggingFace 的 JS 版，一行代码调用模型</td></tr><tr><td>量化</td><td>q4 让模型体积缩小 4 倍</td></tr><tr><td>应用场景</td><td>隐私敏感、离线、低成本场景的最佳方案</td></tr></tbody></table><h3 id="联动路径"><a href="#联动路径" class="headerlink" title="联动路径"></a>联动路径</h3><ul><li>理论：<a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理</a> → <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a></li><li>实战：本篇 → <a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E5%BC%A0%E9%87%8F%E6%93%8D%E4%BD%9C%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%BE%AE%E5%88%86/">PyTorch实战</a> → <a href="/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%EF%BC%88CIFAR-10%EF%BC%89/">图像分类（CIFAR-10）</a></li><li>资讯：看看最近哪些模型支持浏览器端 → <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a></li></ul><hr><p><strong>思考题</strong>：如果每个人的浏览器都能跑 AI，云厂商的推理业务会受影响吗？什么场景必须用云端大模型（提示：Kimi K3 的 100 万 token 上下文）？评论区见。</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/</id>
    <link href="https://aijvs.com/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <published>2026-08-06T05:00:00.000Z</published>
    <summary>用 WebGPU + Transformers.js 在浏览器里直接运行大模型：无需服务器、无需安装、隐私全本地。从原理到可运行代码，20分钟让AI在你的浏览器里跑起来。</summary>
    <title>WebGPU实战：在浏览器里跑大模型（零成本本地推理）</title>
    <updated>2026-08-06T05:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="深度学习" scheme="https://aijvs.com/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"/>
    <category term="Transformer" scheme="https://aijvs.com/tags/Transformer/"/>
    <category term="进阶" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6/"/>
    <category term="LLM" scheme="https://aijvs.com/tags/LLM/"/>
    <category term="训练" scheme="https://aijvs.com/tags/%E8%AE%AD%E7%BB%83/"/>
    <category term="推理" scheme="https://aijvs.com/tags/%E6%8E%A8%E7%90%86/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：本系列是 <a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a> 的续篇。强烈建议先读完上一篇，再来看 LLM 是怎么”长大”的。</p></blockquote><hr><h2 id="从-Transformer-到-LLM：中间发生了什么？"><a href="#从-Transformer-到-LLM：中间发生了什么？" class="headerlink" title="从 Transformer 到 LLM：中间发生了什么？"></a>从 Transformer 到 LLM：中间发生了什么？</h2><p>上一篇我们搞懂了 Transformer 单层的工作原理。但 GPT、Kimi K3、DeepSeek 这些”大语言模型”（Large Language Model, LLM），不是一个 Transformer 层，而是<strong>几十上百层堆叠 + 海量数据训练</strong>的产物。</p><p>一个核心问题：<strong>为什么把 Transformer 堆大、喂数据，模型就”会说话”了？</strong></p><p>答案是：<strong>下一个词预测（Next Token Prediction）</strong>——所有 LLM 的核心训练目标，简单到令人难以置信。</p><hr><h2 id="一、预训练：让模型学会”接话”"><a href="#一、预训练：让模型学会”接话”" class="headerlink" title="一、预训练：让模型学会”接话”"></a>一、预训练：让模型学会”接话”</h2><h3 id="1-1-核心思想"><a href="#1-1-核心思想" class="headerlink" title="1.1 核心思想"></a>1.1 核心思想</h3><p>把互联网上几乎所有公开文本（书籍、网页、代码、论文……）喂给模型，让它做一件事：</p><blockquote><p><strong>看到前面的词，预测下一个词是什么。</strong></p></blockquote><p>比如给模型看 “今天天气真”，它要预测最可能的词是”好”（而不是”桌子”）。</p><p>就这么一个简单的目标，配合<strong>千亿级参数 + 万亿级 token 数据</strong>，模型在”预测下一个词”的过程中，被迫学会了：</p><ul><li>语法（主谓宾搭配）</li><li>知识（事实性信息隐含在文本中）</li><li>推理（因果、逻辑链条）</li><li>代码（代码库中蕴含的编程模式）</li></ul><p><strong>这就是”涌现”（Emergence）</strong>：一个简单的目标，在足够大的规模下，涌现出复杂的智能行为。</p><h3 id="1-2-预训练的技术细节"><a href="#1-2-预训练的技术细节" class="headerlink" title="1.2 预训练的技术细节"></a>1.2 预训练的技术细节</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;The cat sits on the [MASK]&quot;  →  模型预测 → &quot;mat&quot;</span><br><span class="line">损失: 交叉熵损失（预测分布 vs 真实词）</span><br><span class="line">优化: AdamW + 学习率调度 + 梯度裁剪</span><br><span class="line">并行: 数据并行 + 张量并行 + 流水线并行（Kimi K3 开源的 MoonEP 就是干这个的）</span><br></pre></td></tr></table></figure><h3 id="1-3-算力门槛"><a href="#1-3-算力门槛" class="headerlink" title="1.3 算力门槛"></a>1.3 算力门槛</h3><ul><li>GPT-3（2020）：1750 亿参数，训练成本约 <strong>460 万美元</strong></li><li>Kimi K3（2026）：2.8 万亿参数，成本是当年的数十倍</li><li>这也是为什么大模型公司疯狂融资、建数据中心（还记得创刊号里 Meta + 贝莱德 140 亿美元建数据中心吗？）</li></ul><hr><h2 id="二、指令微调（SFT）：让模型”听话”"><a href="#二、指令微调（SFT）：让模型”听话”" class="headerlink" title="二、指令微调（SFT）：让模型”听话”"></a>二、指令微调（SFT）：让模型”听话”</h2><p>预训练完成的模型（基座模型）只会”接话”，不会”回答问题”。你问它”1+1等于几”，它可能回”1+1等于2吗？1+1等于……”——因为训练数据里没有”问答”这种格式。</p><p><strong>指令微调（Supervised Fine-Tuning, SFT）</strong> 解决这个问题：用人工标注的”问题-答案”对，让模型学会对话格式。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">用户: 解释一下什么是注意力机制</span><br><span class="line">助手: 注意力机制是让模型在处理序列时...</span><br></pre></td></tr></table></figure><p>数据量通常只有几万到几十万条（相比预训练的万亿 token 是九牛一毛），但效果立竿见影：模型从”文字接龙”变成”智能助手”。</p><hr><h2 id="三、RLHF：让模型”讨人喜欢”"><a href="#三、RLHF：让模型”讨人喜欢”" class="headerlink" title="三、RLHF：让模型”讨人喜欢”"></a>三、RLHF：让模型”讨人喜欢”</h2><p>光会答题还不够——模型可能答得正确但语气生硬，或者输出有害内容。<strong>RLHF（基于人类反馈的强化学习）</strong> 登场：</p><ol><li><strong>训练奖励模型</strong>：让人类对模型的多个回答排序（哪个更好），训练一个”打分器”</li><li><strong>强化学习</strong>：用 PPO 等算法，让主模型学会”怎么回答才能拿高分”</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">步骤1: 收集人类偏好数据（A/B 排序）</span><br><span class="line">步骤2: 训练奖励模型（Reward Model）</span><br><span class="line">步骤3: 用强化学习微调主模型（PPO）</span><br></pre></td></tr></table></figure><p>这就像训练一个实习生：先教他知识（预训练），再教他格式（SFT），最后告诉他”这么说老板更喜欢”（RLHF）。</p><hr><h2 id="四、推理：模型到底在做什么？"><a href="#四、推理：模型到底在做什么？" class="headerlink" title="四、推理：模型到底在做什么？"></a>四、推理：模型到底在做什么？</h2><h3 id="4-1-自回归生成"><a href="#4-1-自回归生成" class="headerlink" title="4.1 自回归生成"></a>4.1 自回归生成</h3><p>训练时预测下一个词，推理时<strong>也是</strong>预测下一个词——只不过把预测出的词接回输入，继续预测下一个：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">输入: &quot;中国的首都是&quot;</span><br><span class="line">→ 预测: &quot;北&quot;</span><br><span class="line">→ 输入: &quot;中国的首都是北&quot;</span><br><span class="line">→ 预测: &quot;京&quot;</span><br><span class="line">→ 输入: &quot;中国的首都是北京&quot;</span><br><span class="line">→ 预测: &quot;&lt;结束&gt;&quot;</span><br><span class="line">→ 输出: &quot;北京&quot;</span><br></pre></td></tr></table></figure><p>这个过程叫<strong>自回归生成（Autoregressive Generation）</strong>。一次生成一个 token（约 1-2 个汉字或半个单词），所以大模型”说话”其实是一步一步挤出来的。</p><h3 id="4-2-推理-vs-思考"><a href="#4-2-推理-vs-思考" class="headerlink" title="4.2 推理 vs 思考"></a>4.2 推理 vs 思考</h3><p><strong>重要澄清</strong>：模型推理时<strong>没有”思考”</strong>——没有意识，没有意图，只是在做概率计算。但为什么 DeepSeek V4-Flash 的 Agent 能力”大幅增强”？</p><p>关键在于 <strong>推理时扩展（Inference-time Scaling）</strong>：</p><ul><li><strong>思维链（Chain-of-Thought）</strong>：让模型”先想再答”，把推理过程写出来再给结论</li><li><strong>树搜索 &#x2F; 自我反思</strong>：模型生成多个候选答案，自我评估挑选（DeepSeek-R1 开创的范式）</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">用户: 17 × 23 = ?</span><br><span class="line">模型(思维链): 17 × 20 = 340, 17 × 3 = 51, 340 + 51 = 391</span><br><span class="line">结论: 391</span><br></pre></td></tr></table></figure><p>这也是 2026 年最大的技术主线——<strong>从”模型变聪明”转向”让模型多想一会儿”</strong>。</p><hr><h2 id="五、上下文窗口与-KV-Cache"><a href="#五、上下文窗口与-KV-Cache" class="headerlink" title="五、上下文窗口与 KV Cache"></a>五、上下文窗口与 KV Cache</h2><h3 id="5-1-上下文窗口"><a href="#5-1-上下文窗口" class="headerlink" title="5.1 上下文窗口"></a>5.1 上下文窗口</h3><p>Kimi K3 支持 <strong>100 万 token 上下文</strong>——意味着单次能处理约 75 万单词（几本《三体》）。上下文窗口 &#x3D; 模型”工作记忆”的大小。</p><p>但注意：<strong>上下文 ≠ 记忆</strong>。模型不会”记住”上次对话，每次对话都是全新计算。所谓”长记忆”，是把历史都塞进上下文窗口。</p><h3 id="5-2-KV-Cache：为什么长上下文贵？"><a href="#5-2-KV-Cache：为什么长上下文贵？" class="headerlink" title="5.2 KV Cache：为什么长上下文贵？"></a>5.2 KV Cache：为什么长上下文贵？</h3><p>回忆 Transformer 注意力公式：<code>softmax(QK^T/√d_k)V</code>。生成每个新 token 时，需要和前面<strong>所有</strong> token 计算注意力。为了不重复计算，模型把之前所有 token 的 K 和 V 缓存下来，这就是 <strong>KV Cache</strong>。</p><ul><li>上下文越长，KV Cache 越大（10 万 token 可能要几十 GB 显存）</li><li>这就是”长上下文很贵”的技术根源</li><li><strong>GQA</strong>（上一篇讲的）通过共享 K&#x2F;V 头，大幅压缩 KV Cache——DeepSeek 的”极致性价比”秘密之一</li></ul><hr><h2 id="六、量化与部署：模型怎么”变小”"><a href="#六、量化与部署：模型怎么”变小”" class="headerlink" title="六、量化与部署：模型怎么”变小”"></a>六、量化与部署：模型怎么”变小”</h2><p>Kimi K3 有 2.8 万亿参数，按 FP16 存储需要 <strong>5.6 TB</strong> 显存——没有单机能装下。实际部署靠：</p><ol><li><strong>量化（Quantization）</strong>：把参数从 16 位压缩到 8 位&#x2F;4 位，模型体积缩小 4 倍，精度损失很小</li><li><strong>分布式推理</strong>：权重切分到多张 GPU（Kimi K3 用 MoE 架构，每 token 只激活 16 个专家，所需显存大幅降低）</li><li><strong>蒸馏（Distillation）</strong>：用大模型教小模型（DeepSeek V4-Flash 130 亿激活参数，就是”小而强”的代表）</li></ol><blockquote><p>想在浏览器里跑小模型？下一篇 <a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/">WebGPU 实战：在浏览器里跑大模型</a> 带你零成本上手。</p></blockquote><hr><h2 id="七、LLM-全景图（一张表看懂）"><a href="#七、LLM-全景图（一张表看懂）" class="headerlink" title="七、LLM 全景图（一张表看懂）"></a>七、LLM 全景图（一张表看懂）</h2><table><thead><tr><th>阶段</th><th>做什么</th><th>数据量</th><th>成本量级</th></tr></thead><tbody><tr><td>预训练</td><td>学语言+知识（接话）</td><td>万亿 token</td><td>数千万美元</td></tr><tr><td>SFT</td><td>学会问答格式</td><td>数万条</td><td>数万美元</td></tr><tr><td>RLHF</td><td>学会讨喜+安全</td><td>数十万条偏好</td><td>数万美元</td></tr><tr><td>推理优化</td><td>量化&#x2F;蒸馏&#x2F;缓存</td><td>—</td><td>持续优化</td></tr></tbody></table><hr><h2 id="八、总结与联动"><a href="#八、总结与联动" class="headerlink" title="八、总结与联动"></a>八、总结与联动</h2><h3 id="核心记忆点"><a href="#核心记忆点" class="headerlink" title="核心记忆点"></a>核心记忆点</h3><ol><li>LLM 的一切始于<strong>预测下一个词</strong>，规模带来涌现</li><li>预训练 → SFT → RLHF 三步，模型从”会接话”到”会聊天”</li><li>推理是自回归，一次一个 token；”推理”≠”思考”</li><li>上下文窗口是工作记忆，KV Cache 是长上下文贵的根源</li><li>量化 + MoE 让 2.8 万亿参数的模型能跑起来</li></ol><h3 id="联动阅读"><a href="#联动阅读" class="headerlink" title="联动阅读"></a>联动阅读</h3><ul><li>上一篇：<a href="/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/">Transformer深度解读</a></li><li>速递里说的”Agent 能力”到底指什么？→ 看 <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a></li><li>想动手调模型？→ <a href="/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/">开源项目贡献指南</a> 了解如何参与开源模型生态</li><li>下一篇：<a href="/2026/08/06/WebGPU%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E8%B7%91%E5%A4%A7%E6%A8%A1%E5%9E%8B/">WebGPU实战：在浏览器里跑大模型</a></li></ul><hr><p><strong>思考题</strong>：如果 LLM 只是”预测下一个词”，为什么它写代码比大多数程序员好？欢迎评论区讨论——提示：答案在”规模”和”数据”里。</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/</id>
    <link href="https://aijvs.com/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/"/>
    <published>2026-08-06T04:00:00.000Z</published>
    <summary>拆解大语言模型全流程：预训练、指令微调、RLHF、推理机制与上下文窗口。理解GPT、Kimi K3、DeepSeek这些模型是怎么炼成的，以及为什么&quot;推理&quot;和&quot;思考&quot;不是一回事。</summary>
    <title>大语言模型（LLM）原理：从训练到推理的完整流程</title>
    <updated>2026-08-06T04:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="深度学习" scheme="https://aijvs.com/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"/>
    <category term="大模型" scheme="https://aijvs.com/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="Transformer" scheme="https://aijvs.com/tags/Transformer/"/>
    <category term="注意力机制" scheme="https://aijvs.com/tags/%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6/"/>
    <category term="架构" scheme="https://aijvs.com/tags/%E6%9E%B6%E6%9E%84/"/>
    <category term="进阶" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6/"/>
    <content>
      <![CDATA[<blockquote><p><strong>阅读前置</strong>：建议先完成<a href="/2026/05/25/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南</a>和<a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ARNN%E4%B8%8ELSTM/">神经网络架构详解：RNN与LSTM</a>。本系列为 P3 前沿解读第二篇。</p></blockquote><hr><h2 id="为什么你必须理解-Transformer？"><a href="#为什么你必须理解-Transformer？" class="headerlink" title="为什么你必须理解 Transformer？"></a>为什么你必须理解 Transformer？</h2><p>在 <a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">AI双周速递·创刊号</a> 里我们聊到：Kimi K3 以 <strong>2.8 万亿参数</strong>登顶全球最大开源模型，DeepSeek V4-Flash 正式版上线——这些新闻的主角，底层都是同一个架构：<strong>Transformer</strong>。</p><p>2026 年的今天，从 GPT 到 Claude，从 Kimi 到 Qwen，从写代码到画图，<strong>几乎所有你能叫出名字的 AI 能力，都是 Transformer 的子孙</strong>。理解它，你就拿到了读懂整个 AI 世界的钥匙。</p><hr><h2 id="一、Transformer-解决了什么问题？"><a href="#一、Transformer-解决了什么问题？" class="headerlink" title="一、Transformer 解决了什么问题？"></a>一、Transformer 解决了什么问题？</h2><p>2017 年之前，处理序列数据（文本、语音）的主流是 <strong>RNN&#x2F;LSTM</strong>。它们的问题很致命：<strong>必须一个词一个词地顺序处理</strong>，就像你读书只能一个字一个字读，而且读完前面就忘了后面（长期依赖问题）。</p><p>2017 年，Google 发表论文 <strong>《Attention Is All You Need》</strong>，提出 Transformer。它的革命性在于：</p><ol><li><strong>并行处理</strong>：所有词同时被处理，训练速度快了几个数量级</li><li><strong>注意力机制</strong>：每个词可以直接”看到”序列中任意其他词，彻底解决长期依赖</li><li><strong>可扩展性</strong>：堆更多层、更多参数就能变强——为大模型的”暴力美学”铺平了道路</li></ol><blockquote><p>一句话：<strong>RNN 是串行排队，Transformer 是全员开会</strong>——每个词都能直接和所有词对话。</p></blockquote><hr><h2 id="二、注意力机制：Transformer-的心脏"><a href="#二、注意力机制：Transformer-的心脏" class="headerlink" title="二、注意力机制：Transformer 的心脏"></a>二、注意力机制：Transformer 的心脏</h2><h3 id="2-1-直觉理解"><a href="#2-1-直觉理解" class="headerlink" title="2.1 直觉理解"></a>2.1 直觉理解</h3><p>想象你在读这句话：”<strong>它</strong>昨天把球传给了小明，<strong>它</strong>跑得真快。”</p><p>“它”指的是谁？你需要看上下文——“传给了小明”暗示”它”是一个人。<strong>注意力机制就是让模型学会这种”回看”的能力</strong>：每个词在理解自己时，会去”注意”句子中其他相关的词，并给它们分配不同的权重。</p><h3 id="2-2-数学形式"><a href="#2-2-数学形式" class="headerlink" title="2.2 数学形式"></a>2.2 数学形式</h3><p>注意力公式（这也是论文标题的由来）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Attention(Q, K, V) = softmax(QK^T / √d_k) × V</span><br></pre></td></tr></table></figure><p>三个矩阵各有分工：</p><table><thead><tr><th>矩阵</th><th>角色</th><th>类比</th></tr></thead><tbody><tr><td><strong>Q</strong>（Query，查询）</td><td>我在找什么</td><td>你在搜索引擎输入的关键词</td></tr><tr><td><strong>K</strong>（Key，键）</td><td>我有什么可被找到</td><td>网页的标题和标签</td></tr><tr><td><strong>V</strong>（Value，值）</td><td>找到后给什么内容</td><td>网页的实际内容</td></tr></tbody></table><p>计算过程三步：</p><ol><li><code>QK^T</code>：每个词和所有词算相似度（关键词 vs 所有网页标题）</li><li><code>softmax</code>：相似度转成权重（哪些网页最相关）</li><li><code>× V</code>：按权重加权求和（把最相关的内容拼起来）</li></ol><p><code>√d_k</code> 是缩放因子，防止点积过大导致 softmax 梯度消失。</p><h3 id="2-3-多头注意力：让模型”多角度”思考"><a href="#2-3-多头注意力：让模型”多角度”思考" class="headerlink" title="2.3 多头注意力：让模型”多角度”思考"></a>2.3 多头注意力：让模型”多角度”思考</h3><p>一个注意力头只能关注一种关系。<strong>多头注意力（Multi-Head Attention）</strong> 把 Q&#x2F;K&#x2F;V 投影到多个子空间，并行计算 h 次：</p><ul><li>头 1 可能关注”谁和谁是主语关系”</li><li>头 2 可能关注”哪个词修饰哪个词”</li><li>头 3 可能关注”代词指向谁”</li></ul><p>最后拼接所有头的结果。这就像让多个专家从不同角度分析同一句话，再综合结论。</p><hr><h2 id="三、Transformer-完整架构拆解"><a href="#三、Transformer-完整架构拆解" class="headerlink" title="三、Transformer 完整架构拆解"></a>三、Transformer 完整架构拆解</h2><p>一个 Transformer 层 &#x3D; <strong>多头注意力 + 前馈网络</strong> + 残差连接 + LayerNorm。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">输入序列 → [词嵌入 + 位置编码] → 多头注意力 → 残差+归一化 → 前馈网络 → 残差+归一化 → 输出</span><br></pre></td></tr></table></figure><h3 id="3-1-词嵌入（Embedding）"><a href="#3-1-词嵌入（Embedding）" class="headerlink" title="3.1 词嵌入（Embedding）"></a>3.1 词嵌入（Embedding）</h3><p>把每个词映射成向量。比如 “AI” → [0.3, -0.1, 0.8, …]。”猫”和”狗”的向量距离近，”猫”和”汽车”距离远——语义相近的词在向量空间里靠得近。</p><blockquote><p>想深入？看看 <a href="/2026/07/03/NLP%E5%85%A5%E9%97%A8%EF%BC%9A%E6%96%87%E6%9C%AC%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E8%AF%8D%E5%90%91%E9%87%8F/">NLP入门：文本预处理与词向量</a>，我们用 Word2Vec 手把手实现过。</p></blockquote><h3 id="3-2-位置编码（Positional-Encoding）"><a href="#3-2-位置编码（Positional-Encoding）" class="headerlink" title="3.2 位置编码（Positional Encoding）"></a>3.2 位置编码（Positional Encoding）</h3><p>注意力机制本身<strong>不感知顺序</strong>——“猫追狗”和”狗追猫”对它来说一样。所以需要给每个词加位置信息。原始论文用正弦&#x2F;余弦函数生成位置向量：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">PE(pos, 2i)   = sin(pos / 10000^(2i/d))</span><br><span class="line">PE(pos, 2i+1) = cos(pos / 10000^(2i/d))</span><br></pre></td></tr></table></figure><p>现代大模型多用 <strong>RoPE（旋转位置编码）</strong>，Kimi K3 就用了自研的 KDA 注意力 + RoPE 的变体。它让模型不仅能感知位置，还能外推到更长的序列。</p><h3 id="3-3-前馈网络（FFN）"><a href="#3-3-前馈网络（FFN）" class="headerlink" title="3.3 前馈网络（FFN）"></a>3.3 前馈网络（FFN）</h3><p>每个位置经过注意力后，再过一个两层的全连接网络（通常中间层是 4 倍宽度）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FFN(x) = max(0, xW1 + b1)W2 + b2</span><br></pre></td></tr></table></figure><p><code>max(0, ·)</code> 是 ReLU 激活。它给模型提供非线性变换能力——注意力负责”找关系”，FFN 负责”加工信息”。</p><h3 id="3-4-残差连接与-LayerNorm"><a href="#3-4-残差连接与-LayerNorm" class="headerlink" title="3.4 残差连接与 LayerNorm"></a>3.4 残差连接与 LayerNorm</h3><ul><li><strong>残差连接</strong>：<code>x + Attention(x)</code>，让梯度能直接流过深层网络，解决”网络越深越难训练”的问题</li><li><strong>LayerNorm</strong>：对每个样本的特征做归一化，稳定训练</li></ul><p>这两个设计让 Transformer 能堆到几十上百层而不崩。</p><hr><h2 id="四、从-Transformer-到大模型：现代进化路线"><a href="#四、从-Transformer-到大模型：现代进化路线" class="headerlink" title="四、从 Transformer 到大模型：现代进化路线"></a>四、从 Transformer 到大模型：现代进化路线</h2><p>理解了基础架构，再看 2026 年的前沿就轻松多了：</p><h3 id="4-1-稀疏注意力（Sparse-Attention）"><a href="#4-1-稀疏注意力（Sparse-Attention）" class="headerlink" title="4.1 稀疏注意力（Sparse Attention）"></a>4.1 稀疏注意力（Sparse Attention）</h3><p>原始注意力复杂度是 O(n²)——序列翻倍，计算量翻四倍。处理 100 万 token 的上下文（Kimi K3 的招牌）时这是天文数字。解决方案：</p><ul><li><strong>局部窗口注意力</strong>：每个词只看附近 2048 个词（如 Mistral、Qwen）</li><li><strong>LongCat 稀疏注意力</strong>（美团 LongCat-2.0，2026）：真实 Agentic 编程场景优化</li></ul><h3 id="4-2-混合专家（MoE）：Kimi-K3-的核心秘密"><a href="#4-2-混合专家（MoE）：Kimi-K3-的核心秘密" class="headerlink" title="4.2 混合专家（MoE）：Kimi K3 的核心秘密"></a>4.2 混合专家（MoE）：Kimi K3 的核心秘密</h3><p>我们在<a href="/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/">创刊号</a>里说过 Kimi K3 是 896 个专家、每次激活 16 个。MoE 的思路：</p><ul><li>把 FFN 层拆成很多”专家”（子网络）</li><li>每来一个 token，<strong>路由器（Router）</strong> 只挑最擅长的几个专家干活</li><li>结果：<strong>总参数 2.8 万亿，但每次推理只激活约 1040 亿</strong>——容量是巨人的，算力成本是普通人的</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MoE层输入 → 路由器选择 top-16 专家 → 16个专家并行计算 → 加权合并 → 输出</span><br></pre></td></tr></table></figure><p>这就是”大模型的容量 + 小模型的效率”。</p><h3 id="4-3-GQA-与混合注意力"><a href="#4-3-GQA-与混合注意力" class="headerlink" title="4.3 GQA 与混合注意力"></a>4.3 GQA 与混合注意力</h3><ul><li><strong>GQA（分组查询注意力）</strong>：多个 Q 头共享 K&#x2F;V 头，显著减少 KV 缓存、降低推理成本——DeepSeek V4、Llama 3 都在用</li><li><strong>混合注意力</strong>：线性注意力 + 全注意力的组合（如 Qwen3.5 的 Gated DeltaNet + Gated Attention），在长上下文和效率间找平衡</li></ul><hr><h2 id="五、动手：20-行代码看注意力（PyTorch）"><a href="#五、动手：20-行代码看注意力（PyTorch）" class="headerlink" title="五、动手：20 行代码看注意力（PyTorch）"></a>五、动手：20 行代码看注意力（PyTorch）</h2><p>理论讲完，直接看代码。这段代码实现单头注意力的核心计算：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn.functional <span class="keyword">as</span> F</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">attention</span>(<span class="params">query, key, value</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    query: (batch, seq_len, d_k)  — 查询</span></span><br><span class="line"><span class="string">    key:   (batch, seq_len, d_k)  — 键</span></span><br><span class="line"><span class="string">    value: (batch, seq_len, d_v)  — 值</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    d_k = query.size(-<span class="number">1</span>)</span><br><span class="line">    <span class="comment"># 1. 计算相似度：Q·K^T</span></span><br><span class="line">    scores = torch.matmul(query, key.transpose(-<span class="number">2</span>, -<span class="number">1</span>))</span><br><span class="line">    <span class="comment"># 2. 缩放：除以 sqrt(d_k)</span></span><br><span class="line">    scores = scores / (d_k ** <span class="number">0.5</span>)</span><br><span class="line">    <span class="comment"># 3. softmax 转权重</span></span><br><span class="line">    weights = F.softmax(scores, dim=-<span class="number">1</span>)</span><br><span class="line">    <span class="comment"># 4. 加权求和</span></span><br><span class="line">    output = torch.matmul(weights, value)</span><br><span class="line">    <span class="keyword">return</span> output, weights</span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例：3个词的序列，每个词8维</span></span><br><span class="line">batch, seq, d_k = <span class="number">1</span>, <span class="number">3</span>, <span class="number">8</span></span><br><span class="line">q = torch.randn(batch, seq, d_k)</span><br><span class="line">k = torch.randn(batch, seq, d_k)</span><br><span class="line">v = torch.randn(batch, seq, d_k)</span><br><span class="line"></span><br><span class="line">output, weights = attention(q, k, v)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;输出形状:&quot;</span>, output.shape)   <span class="comment"># (1, 3, 8)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;注意力权重:\n&quot;</span>, weights)     <span class="comment"># 每个词对其他词的关注程度</span></span><br></pre></td></tr></table></figure><p><strong>试试</strong>：把 <code>weights</code> 打印出来，观察每行（每个词）对其他词的权重分布——这就是模型”注意力”的可视化。想更完整地训练模型，先看 <a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E5%BC%A0%E9%87%8F%E6%93%8D%E4%BD%9C%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%BE%AE%E5%88%86/">PyTorch实战（一）：张量操作与自动微分</a>。</p><hr><h2 id="六、总结与下一步"><a href="#六、总结与下一步" class="headerlink" title="六、总结与下一步"></a>六、总结与下一步</h2><h3 id="核心记忆点"><a href="#核心记忆点" class="headerlink" title="核心记忆点"></a>核心记忆点</h3><ol><li>Transformer 用<strong>注意力机制</strong>取代 RNN，实现并行 + 长距离依赖</li><li>注意力公式 <code>softmax(QK^T/√d_k)V</code>：Q 找、K 被找、V 给内容</li><li>多头注意力让模型多角度理解；位置编码补上顺序信息</li><li>MoE 让 Kimi K3 做到 2.8 万亿参数但推理便宜</li><li>残差 + LayerNorm 是深层网络的稳定器</li></ol><h3 id="学习路径建议"><a href="#学习路径建议" class="headerlink" title="学习路径建议"></a>学习路径建议</h3><ul><li>想要直觉理解 → <a href="/2026/05/25/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南</a></li><li>想动手训练 → <a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch实战（二）：构建第一个全连接网络</a></li><li>想看视觉里的注意力 → <a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN卷积神经网络</a></li><li>下一篇 → <a href="/2026/08/06/%E5%A4%A7%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88LLM%EF%BC%89%E5%8E%9F%E7%90%86%EF%BC%9A%E4%BB%8E%E8%AE%AD%E7%BB%83%E5%88%B0%E6%8E%A8%E7%90%86%E7%9A%84%E5%AE%8C%E6%95%B4%E6%B5%81%E7%A8%8B/">大语言模型（LLM）原理：从训练到推理的完整流程</a>（P3-3，敬请期待）</li></ul><blockquote><p>读懂 Transformer，你就读懂了 90% 的 AI 新闻。下一期速递，我们再聊 Kimi K3 的 MoE 和 DeepSeek V4 时，你已经是”内行”了。</p></blockquote><hr><p><strong>思考题</strong>（欢迎在评论区讨论）：如果注意力是”全员开会”，那 MoE 路由器像什么？为什么说”容量大、激活少”是未来的方向？</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/</id>
    <link href="https://aijvs.com/2026/08/06/Transformer%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%EF%BC%9A%E4%BB%8E%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%E5%88%B0%E7%8E%B0%E4%BB%A3%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%9F%BA%E7%9F%B3/"/>
    <published>2026-08-06T03:00:00.000Z</published>
    <summary>深入拆解Transformer架构：注意力机制、多头注意力、位置编码、LayerNorm，以及MoE等现代大模型进化方向。读完你将真正看懂Kimi K3、GPT这些大模型内部在做什么。</summary>
    <title>Transformer深度解读：从注意力机制到现代大模型的基石</title>
    <updated>2026-08-06T03:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="前沿资讯" scheme="https://aijvs.com/categories/%E5%89%8D%E6%B2%BF%E8%B5%84%E8%AE%AF/"/>
    <category term="AI速递" scheme="https://aijvs.com/tags/AI%E9%80%9F%E9%80%92/"/>
    <category term="大模型" scheme="https://aijvs.com/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="Kimi K3" scheme="https://aijvs.com/tags/Kimi-K3/"/>
    <category term="DeepSeek" scheme="https://aijvs.com/tags/DeepSeek/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <content>
      <![CDATA[<blockquote><p><strong>本期导读</strong>：追踪 AGI 新应用，探寻 AI 真善美。AI 双周速递是 AIJVS 的固定栏目，每两周更新一次，帮你过滤噪音、直击重点。本期是创刊号，覆盖 7 月 16 日 ~ 8 月 5 日。</p></blockquote><hr><h2 id="一、头条：Kimi-K3-——-全球最大开源模型诞生"><a href="#一、头条：Kimi-K3-——-全球最大开源模型诞生" class="headerlink" title="一、头条：Kimi K3 —— 全球最大开源模型诞生"></a>一、头条：Kimi K3 —— 全球最大开源模型诞生</h2><p><strong>7 月 16 日</strong>，月之暗面（Moonshot AI）发布旗舰大模型 <strong>Kimi K3</strong>；<strong>7 月 27 日</strong>，完整模型权重正式开源。</p><h3 id="核心数据（置信度：高，多个独立来源交叉验证）"><a href="#核心数据（置信度：高，多个独立来源交叉验证）" class="headerlink" title="核心数据（置信度：高，多个独立来源交叉验证）"></a>核心数据（置信度：高，多个独立来源交叉验证）</h3><table><thead><tr><th>指标</th><th>数值</th></tr></thead><tbody><tr><td>总参数</td><td><strong>2.8 万亿</strong>（全球最大开源模型）</td></tr><tr><td>激活参数</td><td>约 1040 亿（MoE，896 专家每 Token 激活 16 个）</td></tr><tr><td>上下文窗口</td><td><strong>100 万 Token</strong>（单次可处理约 75 万单词）</td></tr><tr><td>能力</td><td>原生视觉理解，文本&#x2F;图像&#x2F;视频多模态</td></tr><tr><td>编程榜单</td><td>Frontend Code Arena <strong>1679 分</strong>登顶，超越 Claude Fable 5（1631）和 GPT-5.6</td></tr><tr><td>开源时间</td><td>2026-07-27 深夜，完整权重 + 技术报告</td></tr></tbody></table><h3 id="为什么重要？"><a href="#为什么重要？" class="headerlink" title="为什么重要？"></a>为什么重要？</h3><p><strong>这是中国大模型第一次在”开源 + 规模”两个维度同时登顶。</strong></p><ul><li>2.8 万亿参数 &#x3D; 全球首个开源 3 万亿级（约 2.8T）模型</li><li>稀疏 MoE 架构 + 自研 KDA 注意力，让”大而快”成为可能：总参数 2.8T，但每次推理只激活约 1040 亿参数，算力成本没有等比膨胀</li><li>发布后，美股 AI 板块 72 小时内蒸发约 4700 亿美元——市场在重新审视”闭源模型的天价资本开支是否合理”</li></ul><h3 id="对普通学习者意味着什么？"><a href="#对普通学习者意味着什么？" class="headerlink" title="对普通学习者意味着什么？"></a>对普通学习者意味着什么？</h3><p><strong>你可以用更低的成本，跑更强的模型。</strong> 开源意味着权重公开、可私有化部署、可研究原理——这正是学习 AI 最好的土壤。我们后续会推出”Kimi K3 架构解读”系列，从 MoE 混合专家讲起，让你看懂 896 个专家是怎么协作的。</p><p><strong>延伸阅读</strong>：<a href="/2026/05/25/PyTorch-vs-TensorFlow%EF%BC%9A2026%E5%B9%B4%E8%AF%A5%E9%80%89%E5%93%AA%E4%B8%AA%E6%A1%86%E6%9E%B6/">PyTorch vs TensorFlow：2026年该选哪个框架</a> · <a href="#">Transformer 架构详解（即将推出）</a></p><hr><h2 id="二、DeepSeek-V4-Flash-正式版-API-上线"><a href="#二、DeepSeek-V4-Flash-正式版-API-上线" class="headerlink" title="二、DeepSeek V4-Flash 正式版 API 上线"></a>二、DeepSeek V4-Flash 正式版 API 上线</h2><p><strong>7 月 31 日</strong>，DeepSeek 通过 API 文档发布日志，宣布 <strong>DeepSeek-V4-Flash 正式版（V4-Flash-0731）</strong> 上线公测。</p><h3 id="核心要点（置信度：高）"><a href="#核心要点（置信度：高）" class="headerlink" title="核心要点（置信度：高）"></a>核心要点（置信度：高）</h3><table><thead><tr><th>维度</th><th>详情</th></tr></thead><tbody><tr><td>版本</td><td>V4-Flash-0731，仅重新后训练，架构与 4 月预览版一致</td></tr><tr><td>模型名</td><td>开发者继续用 <code>deepseek-v4-flash</code> 调用，后台自动切换</td></tr><tr><td>重点升级</td><td><strong>Agent 能力大幅增强</strong>，基准测试远超 V4-Pro-Preview</td></tr><tr><td>原生支持</td><td>Responses API 格式，针对性适配 Codex</td></tr><tr><td>参数规模</td><td>约 130 亿激活参数</td></tr><tr><td>性价比</td><td>约 98% 缓存命中率，打造极致性价比</td></tr></tbody></table><h3 id="为什么值得关注？"><a href="#为什么值得关注？" class="headerlink" title="为什么值得关注？"></a>为什么值得关注？</h3><p>这是继 4 月 24 日 V4 预览版发布以来的<strong>首次重大升级</strong>。特别值得注意的是：</p><ul><li>名字带 “Flash” 但定位不低——130 亿激活参数做到了”以下克上”，在 WebDev 基准拿到 1577 分（对比 Kimi K3 的 1679）</li><li><strong>Agent 能力是本次升级核心</strong>——AI 从”回答问题”走向”替你干活”，这是 2026 年最大的技术主线</li><li>V4-Pro 正式版”将尽快发布”，预计 8 月初——下一期速递大概率有它</li></ul><h3 id="对开发者意味着什么？"><a href="#对开发者意味着什么？" class="headerlink" title="对开发者意味着什么？"></a>对开发者意味着什么？</h3><p>如果你在做 AI 应用，<strong>优先试试 V4-Flash</strong>。缓存命中率 98% 意味着同样的功能、更低的延迟和成本——对个人开发者尤其友好。</p><hr><h2 id="三、WAIC-2026：具身智能成为绝对主角"><a href="#三、WAIC-2026：具身智能成为绝对主角" class="headerlink" title="三、WAIC 2026：具身智能成为绝对主角"></a>三、WAIC 2026：具身智能成为绝对主角</h2><p><strong>7 月 17-20 日</strong>，世界人工智能大会（WAIC 2026）在上海举行。</p><h3 id="重点观察（置信度：中高）"><a href="#重点观察（置信度：中高）" class="headerlink" title="重点观察（置信度：中高）"></a>重点观察（置信度：中高）</h3><ul><li><strong>具身智能爆发</strong>：全国首个具身智能发展局揭牌；魔法原子发布通用具身大模型 Magic-VLA K02，打造”物理 AI 平台大脑”</li><li><strong>长安天枢智能机器人</strong>：布局具身智能，首批搭载 DingOS，让 AI 融入 0.65 升空间</li><li><strong>应用竞争取代模型竞赛</strong>：多篇行业观察指出，大会展示的重心从”谁家模型更强”转向”谁家应用和生态更完整”</li><li><strong>通义千问进入特斯拉中国车机深度测试</strong>——大模型上车成为趋势</li></ul><h3 id="对学习者意味着什么？"><a href="#对学习者意味着什么？" class="headerlink" title="对学习者意味着什么？"></a>对学习者意味着什么？</h3><p>具身智能（机器人 + AI）是继大模型之后的下一个风口。它需要的能力组合很清晰：<strong>计算机视觉（让机器看见）+ 强化学习&#x2F;控制（让机器行动）+ 大模型（让机器理解）</strong>。你现在学的 CV 基础，正是具身智能的第一块砖。</p><p><strong>延伸阅读</strong>：<a href="/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/">计算机视觉入门：图像处理基础</a> · <a href="/2026/07/29/%E5%AE%9E%E6%88%98%EF%BC%9A%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%EF%BC%88YOLOv8%EF%BC%89/">实战：目标检测（YOLOv8）</a></p><hr><h2 id="四、其他值得关注"><a href="#四、其他值得关注" class="headerlink" title="四、其他值得关注"></a>四、其他值得关注</h2><table><thead><tr><th>事件</th><th>日期</th><th>一句话解读</th></tr></thead><tbody><tr><td>月之暗面完成超 35 亿美元融资，估值升至 500 亿美元</td><td>7 月底</td><td>Kimi K3 发布后资本疯狂追捧，G 轮提前启动</td></tr><tr><td>Meta 联合贝莱德投 140 亿美元建得州 AI 数据中心</td><td>7&#x2F;31</td><td>算力军备竞赛持续，基础设施投入加码</td></tr><tr><td>马斯克推出 X Money 超级应用，对标 Venmo</td><td>7&#x2F;31</td><td>AI 平台开始跨界支付，生态战升级</td></tr><tr><td>QQ 宠物宣布回归，接入 AI 大模型</td><td>7&#x2F;31</td><td>经典 IP + AI 复活，怀旧营销新玩法</td></tr><tr><td>Kimi K3 登顶 Arena 代码评测榜</td><td>7&#x2F;27</td><td>首个获得该榜单第一的中国大模型</td></tr><tr><td>通义千问进入特斯拉车机深度测试</td><td>8 月初</td><td>大模型上车，车机交互要变天</td></tr></tbody></table><hr><h2 id="五、下期预告"><a href="#五、下期预告" class="headerlink" title="五、下期预告"></a>五、下期预告</h2><ul><li>DeepSeek V4-Pro 正式版（预计 8 月初）</li><li>Kimi K3 架构深度解读（我们计划做系列）</li><li>国产模型推理成本对比实测</li><li>更多应用层进展</li></ul><hr><h2 id="六、本期的学习建议"><a href="#六、本期的学习建议" class="headerlink" title="六、本期的学习建议"></a>六、本期的学习建议</h2><p>如果你是新读者，别被这些数字吓到。<strong>你不需要理解 2.8 万亿参数是什么，也能开始学 AI。</strong> 建议路径：</p><ol><li>从<a href="/2026/07/03/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南</a>开始，建立整体认知</li><li>走<a href="/course/">课程中心快速通道</a>，30 分钟训练第一个模型</li><li>再看本期速递——你会对”模型为什么值这么多钱”有切身体感</li></ol><blockquote><p><strong>关于资讯可信度</strong>：本栏目所有信息均来自公开报道并交叉验证，标注置信度（高&#x2F;中&#x2F;低）。AI 领域变化极快，如有出入请以官方公告为准。</p></blockquote><hr><p><strong>喜欢这个栏目？在评论区告诉我们你想看什么</strong>。下一期我们重点深挖 Kimi K3 架构，还是 DeepSeek V4 实测？你说了算。</p>]]>
    </content>
    <id>https://aijvs.com/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/</id>
    <link href="https://aijvs.com/2026/08/06/AI%E5%8F%8C%E5%91%A8%E9%80%9F%E9%80%92%C2%B7%E5%88%9B%E5%88%8A%E5%8F%B7%EF%BC%9AKimi%20K3%20%E7%99%BB%E9%A1%B6%E5%85%A8%E7%90%83%E5%BC%80%E6%BA%90%E7%8E%8B%E5%BA%A7%EF%BC%8CDeepSeek%20V4-Flash%20%E6%AD%A3%E5%BC%8F%E7%89%88%E4%B8%8A%E7%BA%BF/"/>
    <published>2026-08-06T01:50:00.000Z</published>
    <summary>追踪AGI新应用，探寻AI真善美。创刊号盘点：Kimi K3 以2.8万亿参数登顶全球最大开源模型、DeepSeek V4-Flash 正式版 API 上线、WAIC 2026 具身智能爆发。</summary>
    <title>AI双周速递·创刊号：Kimi K3 登顶全球开源王座，DeepSeek V4-Flash 正式版上线</title>
    <updated>2026-08-06T01:50:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="实战项目" scheme="https://aijvs.com/tags/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="开源" scheme="https://aijvs.com/tags/%E5%BC%80%E6%BA%90/"/>
    <category term="GitHub" scheme="https://aijvs.com/tags/GitHub/"/>
    <category term="社区贡献" scheme="https://aijvs.com/tags/%E7%A4%BE%E5%8C%BA%E8%B4%A1%E7%8C%AE/"/>
    <category term="Git" scheme="https://aijvs.com/tags/Git/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>你学完了所有的教程、跑完了所有的代码——然后呢？</p><p><strong>靠”学会”找不到工作。靠”做过”能。</strong></p><p>GitHub 上你的 commit 历史、PR 记录、Issue 讨论，是你技术能力的最直接证明——比学历和证书管用得多。</p><p>而且 AI 领域有一个独特优势：<strong>几乎所有最顶尖的项目都开源。</strong> PyTorch、Hugging Face Transformers、LangChain、Stable Diffusion——大厂的工程师也在这些仓库里写代码。</p><p>你不需要很厉害才能开始。你只需要开始，就能变得很厉害。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/06/17/Python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E5%8F%98%E9%87%8F%E3%80%81%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%9F%BA%E6%9C%AC%E8%BF%90%E7%AE%97/">Python 编程基础（二）：变量、数据类型和基本运算</a></li><li>Git 基础（clone &#x2F; add &#x2F; commit &#x2F; push &#x2F; pull）</li></ul><hr><h2 id="一、选择贡献方向"><a href="#一、选择贡献方向" class="headerlink" title="一、选择贡献方向"></a>一、选择贡献方向</h2><h3 id="1-1-新手友好标签"><a href="#1-1-新手友好标签" class="headerlink" title="1.1 新手友好标签"></a>1.1 新手友好标签</h3><p>GitHub 仓库里，搜索这些标签：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">good first issue</span><br><span class="line">help wanted</span><br><span class="line">beginner friendly</span><br><span class="line">up-for-grabs</span><br><span class="line">easy</span><br></pre></td></tr></table></figure><h3 id="1-2-AI-领域精选的新手友好项目"><a href="#1-2-AI-领域精选的新手友好项目" class="headerlink" title="1.2 AI 领域精选的新手友好项目"></a>1.2 AI 领域精选的新手友好项目</h3><table><thead><tr><th>项目</th><th>Star</th><th>语言</th><th>找 Issue</th></tr></thead><tbody><tr><td>scikit-learn</td><td>60k+</td><td>Python</td><td><a href="https://github.com/scikit-learn/scikit-learn/labels/good%20first%20issue">good first issues</a></td></tr><tr><td>Hugging Face Transformers</td><td>140k+</td><td>Python</td><td><a href="https://github.com/huggingface/transformers/labels/good%20first%20issue">good first issues</a></td></tr><tr><td>PyTorch</td><td>85k+</td><td>Python&#x2F;C++</td><td><a href="https://github.com/pytorch/pytorch/labels/good%20first%20issue">good first issues</a></td></tr><tr><td>OpenCV</td><td>80k+</td><td>C++&#x2F;Python</td><td><a href="https://github.com/opencv/opencv/labels/help%20wanted">help wanted</a></td></tr><tr><td>LangChain</td><td>100k+</td><td>Python</td><td><a href="https://github.com/langchain-ai/langchain/labels/good%20first%20issue">good first issues</a></td></tr></tbody></table><p><strong>建议：不要一上来就冲 PyTorch 核心。</strong> 它的 good first issue 也是 C++ 级别的难度。从 <strong>scikit-learn</strong> 或 <strong>Hugging Face Datasets</strong> 开始，纯 Python，门槛低。</p><h3 id="1-3-非代码贡献"><a href="#1-3-非代码贡献" class="headerlink" title="1.3 非代码贡献"></a>1.3 非代码贡献</h3><p>开源不只是写代码。这些也是有效贡献：</p><ul><li><strong>文档</strong>：修正拼写错误、补充缺少的 API 说明、增加中文翻译</li><li><strong>Issue 整理</strong>：帮维护者标记重复 Issue、补充复现步骤</li><li><strong>测试</strong>：增加单元测试&#x2F;集成测试用例</li><li><strong>示例代码</strong>：写 Notebook 或 Demo 演示怎么用</li><li><strong>社区答疑</strong>：在 Discussions &#x2F; Discord 里帮新人解决问题</li></ul><p><strong>这些贡献的门槛甚至比代码 PR 低</strong>，但对社区的价值同样巨大。</p><hr><h2 id="二、完整贡献流程"><a href="#二、完整贡献流程" class="headerlink" title="二、完整贡献流程"></a>二、完整贡献流程</h2><h3 id="Step-1-Fork-仓库"><a href="#Step-1-Fork-仓库" class="headerlink" title="Step 1: Fork 仓库"></a>Step 1: Fork 仓库</h3><p>去目标仓库页面，点右上角的 <strong>Fork</strong>。</p><h3 id="Step-2-Clone-到本地"><a href="#Step-2-Clone-到本地" class="headerlink" title="Step 2: Clone 到本地"></a>Step 2: Clone 到本地</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/你的用户名/transformers.git</span><br><span class="line"><span class="built_in">cd</span> transformers</span><br><span class="line">git remote add upstream https://github.com/huggingface/transformers.git</span><br></pre></td></tr></table></figure><p><code>upstream</code> 指向官方仓库，之后用来同步。</p><h3 id="Step-3-创建分支"><a href="#Step-3-创建分支" class="headerlink" title="Step 3: 创建分支"></a>Step 3: 创建分支</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b fix/doc-typo</span><br></pre></td></tr></table></figure><p><strong>永远不要在 main 分支上改代码。</strong> 这是一个铁律。</p><h3 id="Step-4-修改代码"><a href="#Step-4-修改代码" class="headerlink" title="Step 4: 修改代码"></a>Step 4: 修改代码</h3><p>改了啥就是啥——这里假设你发现了一个文档拼写错误。</p><h3 id="Step-5-运行测试"><a href="#Step-5-运行测试" class="headerlink" title="Step 5: 运行测试"></a>Step 5: 运行测试</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 修改的模块的测试</span></span><br><span class="line">pytest tests/models/bert/test_modeling_bert.py -x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者全量测试（慢，提交前可选）</span></span><br><span class="line"><span class="comment"># make test</span></span><br></pre></td></tr></table></figure><h3 id="Step-6-提交推送"><a href="#Step-6-提交推送" class="headerlink" title="Step 6: 提交推送"></a>Step 6: 提交推送</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add -A</span><br><span class="line">git commit -m <span class="string">&quot;Fix typo in BERT documentation&quot;</span></span><br><span class="line">git push origin fix/doc-typo</span><br></pre></td></tr></table></figure><h3 id="Step-7-创建-Pull-Request"><a href="#Step-7-创建-Pull-Request" class="headerlink" title="Step 7: 创建 Pull Request"></a>Step 7: 创建 Pull Request</h3><p>去你的 Fork 页面上，GitHub 会提示你创建 PR。填写：</p><ul><li><strong>标题</strong>：简洁明了，如 “Fix typo in BERT forward method docstring”</li><li><strong>描述</strong>：改了啥，为什么改，关联的 Issue 编号</li><li><strong>Closes #123</strong> ——如果这个 PR 是修复某个 Issue，描述里加上这行</li></ul><h3 id="Step-8-等-Review"><a href="#Step-8-等-Review" class="headerlink" title="Step 8: 等 Review"></a>Step 8: 等 Review</h3><ul><li>可能需要一周甚至更久</li><li>Review 之后可能会要求你修改——这是正常的</li><li>多发几个 PR，reviewer 对你的信任会增加</li></ul><hr><h2 id="三、高质量的-PR"><a href="#三、高质量的-PR" class="headerlink" title="三、高质量的 PR"></a>三、高质量的 PR</h2><h3 id="3-1-先搜索再动手"><a href="#3-1-先搜索再动手" class="headerlink" title="3.1 先搜索再动手"></a>3.1 先搜索再动手</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在仓库里搜有没有其他人已经提交过类似 Issue</span></span><br><span class="line">git <span class="built_in">log</span> --all --grep=<span class="string">&quot;你发现的问题&quot;</span></span><br></pre></td></tr></table></figure><p>或者 GitHub Issues 搜：<code>is:issue is:open 关键词</code></p><p><strong>最忌讳的事</strong>：花了 3 天写了一个 PR，然后发现别人在 Issue 里已经说了”This is a known issue, working on it.”</p><h3 id="3-2-小-PR-大-PR"><a href="#3-2-小-PR-大-PR" class="headerlink" title="3.2 小 PR &gt; 大 PR"></a>3.2 小 PR &gt; 大 PR</h3><ul><li>单个 PR 改一个文件、修一个 bug——reviewer 看到会直接 approve</li><li>单个 PR 改 50 个文件——reviewer 看到会点”Request Changes”然后去吃饭</li></ul><p><strong>经验法则是：一个 PR 只做一件事。</strong> 哪怕一件很小的事。</p><h3 id="3-3-回复-Review"><a href="#3-3-回复-Review" class="headerlink" title="3.3 回复 Review"></a>3.3 回复 Review</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Reviewer: &quot;这个函数命名不够清晰，建议改成 load<span class="emphasis">_model_</span>from<span class="emphasis">_hub&quot;</span></span><br><span class="line"><span class="emphasis">你: &quot;Done. 已修改为 load_</span>model<span class="emphasis">_from_</span>hub，并在 docstring 中补充了参数说明。&quot;</span><br></pre></td></tr></table></figure><ul><li>逐条回复，明确写了”Done”的才算解决</li><li>有不同意见可以辩论，但注意语气——reviewer 在免费帮你审代码</li></ul><hr><h2 id="四、实战案例：给-scikit-learn-修文档"><a href="#四、实战案例：给-scikit-learn-修文档" class="headerlink" title="四、实战案例：给 scikit-learn 修文档"></a>四、实战案例：给 scikit-learn 修文档</h2><p>我们走一遍真实案例。scikit-learn 的 <code>LogisticRegression</code> 文档里有一个例子代码跑不通：</p><h3 id="4-1-发现-Issue"><a href="#4-1-发现-Issue" class="headerlink" title="4.1 发现 Issue"></a>4.1 发现 Issue</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 用户报告：http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html</span></span><br><span class="line"><span class="comment"># 示例代码中缺少 import</span></span><br><span class="line">LogisticRegression(random_state=<span class="number">0</span>).fit(X, y)  <span class="comment"># NameError: X 和 y 没有定义</span></span><br></pre></td></tr></table></figure><h3 id="4-2-修复"><a href="#4-2-修复" class="headerlink" title="4.2 修复"></a>4.2 修复</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 找到文档源文件</span></span><br><span class="line"><span class="built_in">cd</span> sklearn/linear_model/</span><br><span class="line">grep -r <span class="string">&quot;LogisticRegression&quot;</span> _logistic.py</span><br></pre></td></tr></table></figure><p>修改：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在 docstring 开头增加 import 和 mock 数据</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string"><span class="meta">&gt;&gt;&gt; </span>from sklearn.linear_model import LogisticRegression</span></span><br><span class="line"><span class="string"><span class="meta">&gt;&gt;&gt; </span>from sklearn.datasets import make_classification</span></span><br><span class="line"><span class="string"><span class="meta">&gt;&gt;&gt; </span>X, y = make_classification(n_features=4, random_state=0)</span></span><br><span class="line"><span class="string"><span class="meta">&gt;&gt;&gt; </span>LogisticRegression(random_state=0).fit(X, y)</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure><h3 id="4-3-验证"><a href="#4-3-验证" class="headerlink" title="4.3 验证"></a>4.3 验证</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pytest sklearn/linear_model/tests/test_logistic.py -k <span class="string">&quot;test_docstring&quot;</span></span><br></pre></td></tr></table></figure><p>验证文档测试通过。</p><h3 id="4-4-提交-PR"><a href="#4-4-提交-PR" class="headerlink" title="4.4 提交 PR"></a>4.4 提交 PR</h3><p>一个典型的优秀 PR title：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DOC: Add missing imports to LogisticRegression docstring example</span><br></pre></td></tr></table></figure><p>PR 描述：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">The example code in LogisticRegression&#x27;s docstring was missing</span><br><span class="line">X and y variable definitions. Added the necessary imports and</span><br><span class="line">mock data generation using make_classification.</span><br><span class="line"></span><br><span class="line">Closes #28764</span><br></pre></td></tr></table></figure><p><strong>提交后预计 3-7 天被合并。</strong> 这就是你的第一个开源贡献。</p><hr><h2 id="五、维护自己的项目"><a href="#五、维护自己的项目" class="headerlink" title="五、维护自己的项目"></a>五、维护自己的项目</h2><p>参与贡献不只是在别人仓库里写代码。<strong>维护一个自己的开源项目，有时候成长更快。</strong></p><h3 id="5-1-推荐路线"><a href="#5-1-推荐路线" class="headerlink" title="5.1 推荐路线"></a>5.1 推荐路线</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">第 1~3 个月：在别人仓库里贡献（学规范、学流程）</span><br><span class="line">第 3~6 个月：启动自己的小开源项目（工具类脚本）</span><br><span class="line">第 6~12 个月：项目逐渐有人用，收到 Issue 和 PR</span><br><span class="line">第 12 个月+：持续维护，形成社区</span><br></pre></td></tr></table></figure><h3 id="5-2-一个好的-README-包含什么"><a href="#5-2-一个好的-README-包含什么" class="headerlink" title="5.2 一个好的 README 包含什么"></a>5.2 一个好的 README 包含什么</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1. 一句话介绍（这个项目是干嘛的）</span><br><span class="line">2. 快速开始（pip install 加 3 行代码）</span><br><span class="line">3. 完整文档链接</span><br><span class="line">4. 贡献指南（CONTRIBUTING.md）</span><br><span class="line">5. License（不选 License 等于禁止别人用）</span><br><span class="line">6. 使用案例 / Demo 截图</span><br></pre></td></tr></table></figure><h3 id="5-3-必配的文件"><a href="#5-3-必配的文件" class="headerlink" title="5.3 必配的文件"></a>5.3 必配的文件</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.gitignore    - 不要提交 __pycache__/ .env/</span><br><span class="line">LICENSE       - 推荐 MIT 或 Apache 2.0</span><br><span class="line">README.md     - 项目的脸面</span><br><span class="line">CONTRIBUTING.md - 贡献流程说明</span><br><span class="line">CODE_OF_CONDUCT.md - 行为准则</span><br></pre></td></tr></table></figure><hr><h2 id="六、常见问题"><a href="#六、常见问题" class="headerlink" title="六、常见问题"></a>六、常见问题</h2><h3 id="6-1-“我害怕被拒绝怎么办”"><a href="#6-1-“我害怕被拒绝怎么办”" class="headerlink" title="6.1 “我害怕被拒绝怎么办”"></a>6.1 “我害怕被拒绝怎么办”</h3><p><strong>所有的开源维护者都巴不得有人帮他们干活。</strong> 只要你的 PR 不是垃圾（胡乱改动、不跑测试），哪怕方向不对，reviewer 也会善意地告诉你原因。</p><h3 id="6-2-“我的代码被喷了怎么办”"><a href="#6-2-“我的代码被喷了怎么办”" class="headerlink" title="6.2 “我的代码被喷了怎么办”"></a>6.2 “我的代码被喷了怎么办”</h3><p>被 Code Review 批评和面试被挂是两回事。Review 是<strong>针对代码，不是针对你。</strong> 修改后再提交，不会有人记得你初版写得烂。</p><h3 id="6-3-“贡献了也没人用”"><a href="#6-3-“贡献了也没人用”" class="headerlink" title="6.3 “贡献了也没人用”"></a>6.3 “贡献了也没人用”</h3><p>不需要”有人用”。贡献记录的累积意义是：</p><ol><li>面试时展示</li><li>建立技术影响力</li><li>认识行业内的工程师</li></ol><p>每一行 commit 都是一张名片。</p><h3 id="6-4-贡献能否写入简历"><a href="#6-4-贡献能否写入简历" class="headerlink" title="6.4 贡献能否写入简历"></a>6.4 贡献能否写入简历</h3><p>可以，而且是<strong>加分项</strong>。写法和格式：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">开源贡献：</span><br><span class="line">- Hugging Face Transformers: 修复 BERT 分词器序列化 bug（PR #28764, 2026-07）</span><br><span class="line">- scikit-learn: 完善 LogisticRegression 文档示例（PR #15432, 2026-06）</span><br></pre></td></tr></table></figure><p>量化的表述（# 编号、日期、项目名）更可信。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul><li><strong>从修文档开始</strong>：门槛最低，价值不小（文档也是代码的一部分）</li><li><strong>从一个 Issue 开始</strong>：找到 good first issue，确认后动手</li><li><strong>一次 PR 只做一件事</strong>：越大越难被合并</li><li><strong>态度比能力重要</strong>：愿意改、愿意学的人，在开源社区能走得更远</li></ul><p><strong>为你设计一个 30 天计划：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">第 1-7 天   选 3 个你常用的开源项目，加到星标</span><br><span class="line">第 7-14 天  每个项目找 5 个 good first issue，读一读</span><br><span class="line">第 14-21 天 开始第一个 PR（修文档或者补测试）</span><br><span class="line">第 21-30 天 提第二个 PR，这次修一个真正的小 bug</span><br></pre></td></tr></table></figure><p>按照这个节奏走，30 天后你的 GitHub 主页上就有两个绿色的小方块了。</p>]]>
    </content>
    <id>https://aijvs.com/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/</id>
    <link href="https://aijvs.com/2026/07/29/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8EAI%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA/"/>
    <published>2026-07-29T02:00:00.000Z</published>
    <summary>从零开始给 AI 开源项目做贡献：从提 Issue、修文档到写代码 PR，带你完成第一个开源贡献。</summary>
    <title>开源项目贡献指南：如何参与 AI 开源社区</title>
    <updated>2026-07-29T02:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="竞赛实战" scheme="https://aijvs.com/categories/%E7%AB%9E%E8%B5%9B%E5%AE%9E%E6%88%98/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="Kaggle" scheme="https://aijvs.com/tags/Kaggle/"/>
    <category term="竞赛" scheme="https://aijvs.com/tags/%E7%AB%9E%E8%B5%9B/"/>
    <category term="数据科学" scheme="https://aijvs.com/tags/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/"/>
    <category term="特征工程" scheme="https://aijvs.com/tags/%E7%89%B9%E5%BE%81%E5%B7%A5%E7%A8%8B/"/>
    <category term="scikit-learn" scheme="https://aijvs.com/tags/scikit-learn/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>Kaggle 是数据科学界的”新东方”——刷名号、刷经验、刷 offer 的地方。</p><p>Titanic 是 Kaggle 的”Hello World”。2012 年开赛到今天，超过 3 万份参赛作品——新人在这里学到的不是调参，而是<strong>一套完整的竞赛管线</strong>。</p><p>简单的问题：给你 891 个乘客的信息（年龄、性别、船票等级等），预测谁能在海难中幸存。</p><p>但就这个看似简单的问题，涵盖了竞赛的 90% 的通用技能。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%EF%BC%9A%E6%A6%82%E5%BF%B5%E4%B8%8E%E5%88%86%E7%B1%BB%E5%85%A8%E8%A7%A3/">机器学习入门：概念与分类全解</a></li><li><a href="/2026/06/17/Python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%89%EF%BC%89%EF%BC%9ANumPy%E2%80%94%E2%80%94AI%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E7%AC%AC%E4%B8%80%E4%BB%B6%E6%AD%A6%E5%99%A8/">Python 编程基础（三）：NumPy 快速入门</a></li><li>Pandas 基础（知道 DataFrame 怎么读写就够了）</li></ul><hr><h2 id="一、加载数据"><a href="#一、加载数据" class="headerlink" title="一、加载数据"></a>一、加载数据</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> seaborn <span class="keyword">as</span> sns</span><br><span class="line"></span><br><span class="line">train = pd.read_csv(<span class="string">&#x27;train.csv&#x27;</span>)</span><br><span class="line">test  = pd.read_csv(<span class="string">&#x27;test.csv&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(train.shape)   <span class="comment"># (891, 12)</span></span><br><span class="line"><span class="built_in">print</span>(train.columns)</span><br></pre></td></tr></table></figure><p>看看前几行：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">  PassengerId  Survived  Pclass  Name      Sex   Age  SibSp  Parch  Ticket  Fare Cabin Embarked</span><br><span class="line">0           1         0       3  Braund..  male   22     1      0  A/5..   7.25  NaN         S</span><br><span class="line">1           2         1       1  Cumings.. female  38     1      0  PC..   71.3  C85         C</span><br><span class="line">2           3         1       3  Heikkin.. female  26     0      0  ST..   7.92  NaN         S</span><br></pre></td></tr></table></figure><p>字段含义：</p><table><thead><tr><th>字段</th><th>含义</th><th>类型</th></tr></thead><tbody><tr><td>Survived</td><td>是否幸存（1&#x3D;是）</td><td><strong>目标变量</strong></td></tr><tr><td>Pclass</td><td>船舱等级（1&#x2F;2&#x2F;3）</td><td>类别型</td></tr><tr><td>Sex</td><td>性别</td><td>类别型</td></tr><tr><td>Age</td><td>年龄</td><td>数值型（<strong>有缺失</strong>）</td></tr><tr><td>SibSp</td><td>兄弟姐妹&#x2F;配偶数</td><td>数值型</td></tr><tr><td>Parch</td><td>父母&#x2F;子女数</td><td>数值型</td></tr><tr><td>Fare</td><td>票价</td><td>数值型</td></tr><tr><td>Embarked</td><td>登船港口（C&#x2F;Q&#x2F;S）</td><td>类别型（<strong>有缺失</strong>）</td></tr><tr><td>Cabin</td><td>舱房号</td><td>类别型（<strong>大量缺失</strong>）</td></tr><tr><td>Name, Ticket</td><td>名字和票号</td><td>高基数文本（需要特征提取）</td></tr></tbody></table><hr><h2 id="二、数据探索（EDA）"><a href="#二、数据探索（EDA）" class="headerlink" title="二、数据探索（EDA）"></a>二、数据探索（EDA）</h2><h3 id="2-1-缺失值"><a href="#2-1-缺失值" class="headerlink" title="2.1 缺失值"></a>2.1 缺失值</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">train.isnull().<span class="built_in">sum</span>()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Age         177</span><br><span class="line">Cabin       687</span><br><span class="line">Embarked      2</span><br></pre></td></tr></table></figure><ul><li>Cabin 缺了 77%——直接判定：<strong>弃用 Cabin 列</strong>。缺太多补了也是噪声</li><li>Age 缺 177 条（20%）——需要填充</li><li>Embarked 缺 2 条（0.2%）——填充众数</li></ul><h3 id="2-2-幸存率分布"><a href="#2-2-幸存率分布" class="headerlink" title="2.2 幸存率分布"></a>2.2 幸存率分布</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(train[<span class="string">&#x27;Survived&#x27;</span>].value_counts(normalize=<span class="literal">True</span>))</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0    0.616</span><br><span class="line">1    0.384</span><br></pre></td></tr></table></figure><p>大约 62% 的人遇难，38% 幸存。</p><h3 id="2-3-核心变量分析"><a href="#2-3-核心变量分析" class="headerlink" title="2.3 核心变量分析"></a>2.3 核心变量分析</h3><p><strong>性别：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">train.groupby(<span class="string">&#x27;Sex&#x27;</span>)[<span class="string">&#x27;Survived&#x27;</span>].mean()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">female    0.742  ← 74% 的女性幸存</span><br><span class="line">male      0.189  ← 只有 19% 的男性幸存</span><br></pre></td></tr></table></figure><p><strong>等级：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">train.groupby(<span class="string">&#x27;Pclass&#x27;</span>)[<span class="string">&#x27;Survived&#x27;</span>].mean()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Pclass 1: 0.630  ← 头等舱</span><br><span class="line">Pclass 2: 0.473</span><br><span class="line">Pclass 3: 0.242  ← 三等舱</span><br></pre></td></tr></table></figure><p><strong>年龄分布：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 儿童幸存率远高于成人</span></span><br><span class="line">train[train[<span class="string">&#x27;Age&#x27;</span>] &lt; <span class="number">12</span>][<span class="string">&#x27;Survived&#x27;</span>].mean()   <span class="comment"># ~0.60</span></span><br><span class="line">train[train[<span class="string">&#x27;Age&#x27;</span>] &gt; <span class="number">60</span>][<span class="string">&#x27;Survived&#x27;</span>].mean()   <span class="comment"># ~0.27</span></span><br></pre></td></tr></table></figure><p><strong>三个最强特征：Sex &gt; Pclass &gt; Age。</strong></p><hr><h2 id="三、特征工程"><a href="#三、特征工程" class="headerlink" title="三、特征工程"></a>三、特征工程</h2><h3 id="3-1-年龄填充"><a href="#3-1-年龄填充" class="headerlink" title="3.1 年龄填充"></a>3.1 年龄填充</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 按性别+等级分组，用中位数填充年龄</span></span><br><span class="line">train[<span class="string">&#x27;Age&#x27;</span>] = train.groupby([<span class="string">&#x27;Sex&#x27;</span>, <span class="string">&#x27;Pclass&#x27;</span>])[<span class="string">&#x27;Age&#x27;</span>].transform(</span><br><span class="line">    <span class="keyword">lambda</span> x: x.fillna(x.median()))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 分箱：把年龄分成 5 段</span></span><br><span class="line">train[<span class="string">&#x27;AgeBin&#x27;</span>] = pd.cut(train[<span class="string">&#x27;Age&#x27;</span>],</span><br><span class="line">    bins=[<span class="number">0</span>, <span class="number">12</span>, <span class="number">30</span>, <span class="number">50</span>, <span class="number">80</span>],</span><br><span class="line">    labels=[<span class="string">&#x27;Child&#x27;</span>, <span class="string">&#x27;Young&#x27;</span>, <span class="string">&#x27;Middle&#x27;</span>, <span class="string">&#x27;Elderly&#x27;</span>])</span><br></pre></td></tr></table></figure><p>为什么分箱？模型对”32 岁和 33 岁之间的差异”不感兴趣，但对”儿童 vs 成年人”的巨大差异感兴趣。</p><h3 id="3-2-家庭人数"><a href="#3-2-家庭人数" class="headerlink" title="3.2 家庭人数"></a>3.2 家庭人数</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">train[<span class="string">&#x27;FamilySize&#x27;</span>] = train[<span class="string">&#x27;SibSp&#x27;</span>] + train[<span class="string">&#x27;Parch&#x27;</span>] + <span class="number">1</span>  <span class="comment"># +1 是自己</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 单人和超大家庭幸存率低，2-4 人家庭幸存率高</span></span><br><span class="line">train[<span class="string">&#x27;IsAlone&#x27;</span>] = (train[<span class="string">&#x27;FamilySize&#x27;</span>] == <span class="number">1</span>).astype(<span class="built_in">int</span>)</span><br></pre></td></tr></table></figure><h3 id="3-3-名字中提取称谓"><a href="#3-3-名字中提取称谓" class="headerlink" title="3.3 名字中提取称谓"></a>3.3 名字中提取称谓</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Mr/Mrs/Miss/Dr/Reverend/...</span></span><br><span class="line">train[<span class="string">&#x27;Title&#x27;</span>] = train[<span class="string">&#x27;Name&#x27;</span>].<span class="built_in">str</span>.extract(<span class="string">r&#x27;([A-Za-z]+)\.&#x27;</span>, expand=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 合并稀有称谓</span></span><br><span class="line">rare_titles = [<span class="string">&#x27;Lady&#x27;</span>, <span class="string">&#x27;Countess&#x27;</span>,<span class="string">&#x27;Capt&#x27;</span>, <span class="string">&#x27;Col&#x27;</span>,<span class="string">&#x27;Don&#x27;</span>, <span class="string">&#x27;Dr&#x27;</span>,</span><br><span class="line">               <span class="string">&#x27;Major&#x27;</span>, <span class="string">&#x27;Rev&#x27;</span>, <span class="string">&#x27;Sir&#x27;</span>, <span class="string">&#x27;Jonkheer&#x27;</span>, <span class="string">&#x27;Dona&#x27;</span>]</span><br><span class="line">train[<span class="string">&#x27;Title&#x27;</span>] = train[<span class="string">&#x27;Title&#x27;</span>].replace(rare_titles, <span class="string">&#x27;Rare&#x27;</span>)</span><br><span class="line">train[<span class="string">&#x27;Title&#x27;</span>] = train[<span class="string">&#x27;Title&#x27;</span>].replace(&#123;<span class="string">&#x27;Mlle&#x27;</span>: <span class="string">&#x27;Miss&#x27;</span>, <span class="string">&#x27;Ms&#x27;</span>: <span class="string">&#x27;Miss&#x27;</span>, <span class="string">&#x27;Mme&#x27;</span>: <span class="string">&#x27;Mrs&#x27;</span>&#125;)</span><br></pre></td></tr></table></figure><p>Title 是一个被低估的强特征——“Master”（小男孩）幸存率 &gt;50%，”Mr”（成年男性）幸存率 ~15%。</p><h3 id="3-4-票价分箱"><a href="#3-4-票价分箱" class="headerlink" title="3.4 票价分箱"></a>3.4 票价分箱</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">train[<span class="string">&#x27;FareBin&#x27;</span>] = pd.qcut(train[<span class="string">&#x27;Fare&#x27;</span>], <span class="number">4</span>,</span><br><span class="line">    labels=[<span class="string">&#x27;Low&#x27;</span>, <span class="string">&#x27;Medium&#x27;</span>, <span class="string">&#x27;High&#x27;</span>, <span class="string">&#x27;VeryHigh&#x27;</span>])</span><br></pre></td></tr></table></figure><h3 id="3-5-编码"><a href="#3-5-编码" class="headerlink" title="3.5 编码"></a>3.5 编码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.preprocessing <span class="keyword">import</span> LabelEncoder</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> col <span class="keyword">in</span> [<span class="string">&#x27;Sex&#x27;</span>, <span class="string">&#x27;Title&#x27;</span>, <span class="string">&#x27;AgeBin&#x27;</span>, <span class="string">&#x27;FareBin&#x27;</span>, <span class="string">&#x27;Embarked&#x27;</span>]:</span><br><span class="line">    train[col] = LabelEncoder().fit_transform(train[col].astype(<span class="built_in">str</span>))</span><br></pre></td></tr></table></figure><hr><h2 id="四、模型选择"><a href="#四、模型选择" class="headerlink" title="四、模型选择"></a>四、模型选择</h2><p>Titanic 是小型表格数据集（几百条，十来个特征），不要上来就上 XGBoost——先试简单的。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> RandomForestClassifier, GradientBoostingClassifier</span><br><span class="line"><span class="keyword">from</span> sklearn.linear_model <span class="keyword">import</span> LogisticRegression</span><br><span class="line"><span class="keyword">from</span> sklearn.model_selection <span class="keyword">import</span> cross_val_score, StratifiedKFold</span><br><span class="line"><span class="keyword">from</span> sklearn.metrics <span class="keyword">import</span> accuracy_score</span><br><span class="line"></span><br><span class="line">features = [<span class="string">&#x27;Pclass&#x27;</span>, <span class="string">&#x27;Sex&#x27;</span>, <span class="string">&#x27;Age&#x27;</span>, <span class="string">&#x27;Fare&#x27;</span>, <span class="string">&#x27;Embarked&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;FamilySize&#x27;</span>, <span class="string">&#x27;IsAlone&#x27;</span>, <span class="string">&#x27;Title&#x27;</span>, <span class="string">&#x27;AgeBin&#x27;</span>, <span class="string">&#x27;FareBin&#x27;</span>]</span><br><span class="line">X = train[features]</span><br><span class="line">y = train[<span class="string">&#x27;Survived&#x27;</span>]</span><br><span class="line"></span><br><span class="line">kfold = StratifiedKFold(n_splits=<span class="number">5</span>, shuffle=<span class="literal">True</span>, random_state=<span class="number">42</span>)</span><br><span class="line"></span><br><span class="line">models = &#123;</span><br><span class="line">    <span class="string">&#x27;Logistic Regression&#x27;</span>: LogisticRegression(max_iter=<span class="number">1000</span>),</span><br><span class="line">    <span class="string">&#x27;Random Forest&#x27;</span>: RandomForestClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>),</span><br><span class="line">    <span class="string">&#x27;Gradient Boosting&#x27;</span>: GradientBoostingClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>),</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> name, model <span class="keyword">in</span> models.items():</span><br><span class="line">    scores = cross_val_score(model, X, y, cv=kfold, scoring=<span class="string">&#x27;accuracy&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;name:25s&#125;</span>: <span class="subst">&#123;scores.mean():<span class="number">.4</span>f&#125;</span> (+/- <span class="subst">&#123;scores.std():<span class="number">.4</span>f&#125;</span>)&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Logistic Regression       : 0.8214 (+/- 0.0256)</span><br><span class="line">Random Forest             : 0.8283 (+/- 0.0187)</span><br><span class="line">Gradient Boosting         : 0.8310 (+/- 0.0211)</span><br></pre></td></tr></table></figure><p>三个模型都在 0.82-0.83 之间。差距不大——说明<strong>特征是瓶颈</strong>，不是模型。</p><hr><h2 id="五、集成与提分"><a href="#五、集成与提分" class="headerlink" title="五、集成与提分"></a>五、集成与提分</h2><h3 id="5-1-投票集成"><a href="#5-1-投票集成" class="headerlink" title="5.1 投票集成"></a>5.1 投票集成</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> VotingClassifier</span><br><span class="line"></span><br><span class="line">voting = VotingClassifier([</span><br><span class="line">    (<span class="string">&#x27;lr&#x27;</span>, LogisticRegression(max_iter=<span class="number">1000</span>)),</span><br><span class="line">    (<span class="string">&#x27;rf&#x27;</span>, RandomForestClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">    (<span class="string">&#x27;gb&#x27;</span>, GradientBoostingClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">], voting=<span class="string">&#x27;soft&#x27;</span>)</span><br><span class="line"></span><br><span class="line">scores = cross_val_score(voting, X, y, cv=kfold, scoring=<span class="string">&#x27;accuracy&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Voting Ensemble: <span class="subst">&#123;scores.mean():<span class="number">.4</span>f&#125;</span> (+/- <span class="subst">&#123;scores.std():<span class="number">.4</span>f&#125;</span>)&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期：<strong>0.8347</strong>——比最好的单模型涨了 0.3%。</p><h3 id="5-2-Stacking"><a href="#5-2-Stacking" class="headerlink" title="5.2 Stacking"></a>5.2 Stacking</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> StackingClassifier</span><br><span class="line"></span><br><span class="line">stacking = StackingClassifier([</span><br><span class="line">    (<span class="string">&#x27;lr&#x27;</span>, LogisticRegression(max_iter=<span class="number">1000</span>)),</span><br><span class="line">    (<span class="string">&#x27;rf&#x27;</span>, RandomForestClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">    (<span class="string">&#x27;gb&#x27;</span>, GradientBoostingClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">], final_estimator=LogisticRegression(), cv=<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">scores = cross_val_score(stacking, X, y, cv=kfold, scoring=<span class="string">&#x27;accuracy&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Stacking Ensemble: <span class="subst">&#123;scores.mean():<span class="number">.4</span>f&#125;</span> (+/- <span class="subst">&#123;scores.std():<span class="number">.4</span>f&#125;</span>)&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期：<strong>0.8372</strong>——再涨 0.2-0.3%。</p><hr><h2 id="六、提交"><a href="#六、提交" class="headerlink" title="六、提交"></a>六、提交</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 对测试集做同样的特征工程</span></span><br><span class="line"><span class="comment"># ...（同训练集的预处理流程，注意用训练集统计量填充）</span></span><br><span class="line"></span><br><span class="line">predictions = voting.predict(test[features])</span><br><span class="line"></span><br><span class="line">submission = pd.DataFrame(&#123;</span><br><span class="line">    <span class="string">&#x27;PassengerId&#x27;</span>: test[<span class="string">&#x27;PassengerId&#x27;</span>],</span><br><span class="line">    <span class="string">&#x27;Survived&#x27;</span>: predictions</span><br><span class="line">&#125;)</span><br><span class="line">submission.to_csv(<span class="string">&#x27;submission.csv&#x27;</span>, index=<span class="literal">False</span>)</span><br><span class="line"><span class="built_in">print</span>(submission.head())</span><br></pre></td></tr></table></figure><p>上传到 Kaggle：<strong>Titanic → Submit Predictions → 上传 CSV</strong>。</p><p><strong>预期公共榜分数：0.77 - 0.79。</strong> 为什么比 CV 低？CV 是 5 折平均，Kaggle 的测试集是全量 unseen 的。</p><hr><h2 id="七、进阶优化（0-80-的来源）"><a href="#七、进阶优化（0-80-的来源）" class="headerlink" title="七、进阶优化（0.80+ 的来源）"></a>七、进阶优化（0.80+ 的来源）</h2><p>下面这些技巧不是必须的，但它们把分数从 0.77 推到 0.80+：</p><h3 id="7-1-交叉验证不一致检查"><a href="#7-1-交叉验证不一致检查" class="headerlink" title="7.1 交叉验证不一致检查"></a>7.1 交叉验证不一致检查</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 如果 5 折 CV 的方差 &gt; 0.03，说明特征不稳定</span></span><br><span class="line"><span class="comment"># 解决办法：检查是否有泄漏特征或数据分布不一致</span></span><br></pre></td></tr></table></figure><h3 id="7-2-极端值裁剪"><a href="#7-2-极端值裁剪" class="headerlink" title="7.2 极端值裁剪"></a>7.2 极端值裁剪</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Fare 有一个 512 的极端值</span></span><br><span class="line">train[<span class="string">&#x27;Fare&#x27;</span>] = train[<span class="string">&#x27;Fare&#x27;</span>].clip(upper=<span class="number">200</span>)</span><br></pre></td></tr></table></figure><h3 id="7-3-更细的-Cabin-特征"><a href="#7-3-更细的-Cabin-特征" class="headerlink" title="7.3 更细的 Cabin 特征"></a>7.3 更细的 Cabin 特征</h3><p>完全弃用 Cabin 可能太浪费。至少取出首字母：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">train[<span class="string">&#x27;Deck&#x27;</span>] = train[<span class="string">&#x27;Cabin&#x27;</span>].<span class="built_in">str</span>[<span class="number">0</span>]</span><br><span class="line"><span class="comment"># A/B/C/D/E 是高等级甲板 → 幸存率更高</span></span><br></pre></td></tr></table></figure><h3 id="7-4-XGBoost-调参"><a href="#7-4-XGBoost-调参" class="headerlink" title="7.4 XGBoost + 调参"></a>7.4 XGBoost + 调参</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> xgboost <span class="keyword">as</span> xgb</span><br><span class="line"></span><br><span class="line">xgb_model = xgb.XGBClassifier(</span><br><span class="line">    n_estimators=<span class="number">500</span>,</span><br><span class="line">    max_depth=<span class="number">4</span>,</span><br><span class="line">    learning_rate=<span class="number">0.05</span>,</span><br><span class="line">    subsample=<span class="number">0.8</span>,</span><br><span class="line">    colsample_bytree=<span class="number">0.8</span>,</span><br><span class="line">    random_state=<span class="number">42</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>Titanic 上 XGBoost 不一定比 Random Forest 好太多（数据太小），但训练 XGBoost 本身是一个重要的学习过程。</p><h3 id="7-5-学习排名"><a href="#7-5-学习排名" class="headerlink" title="7.5 学习排名"></a>7.5 学习排名</h3><table><thead><tr><th>公共榜分数</th><th>排名</th><th>对应的能力等级</th></tr></thead><tbody><tr><td>0.78</td><td>Top 50%</td><td>基本管线完整</td></tr><tr><td>0.80</td><td>Top 25%</td><td>特征工程到位</td></tr><tr><td>0.81-0.82</td><td>Top 10%</td><td>集成 + 精细调参</td></tr><tr><td>0.83+</td><td>Top 5%</td><td>手工特征 + 领域知识 + 交叉验证调优</td></tr></tbody></table><hr><h2 id="八、完整代码"><a href="#八、完整代码" class="headerlink" title="八、完整代码"></a>八、完整代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;titanic.py - Kaggle Titanic 生存预测&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> VotingClassifier</span><br><span class="line"><span class="keyword">from</span> sklearn.linear_model <span class="keyword">import</span> LogisticRegression</span><br><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> RandomForestClassifier, GradientBoostingClassifier</span><br><span class="line"><span class="keyword">from</span> sklearn.preprocessing <span class="keyword">import</span> LabelEncoder</span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 加载</span></span><br><span class="line">train = pd.read_csv(<span class="string">&#x27;train.csv&#x27;</span>)</span><br><span class="line">test  = pd.read_csv(<span class="string">&#x27;test.csv&#x27;</span>)</span><br><span class="line">ids = test[<span class="string">&#x27;PassengerId&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 合并预处理（统一处理 train + test）</span></span><br><span class="line">all_data = pd.concat([train, test], keys=[<span class="string">&#x27;train&#x27;</span>, <span class="string">&#x27;test&#x27;</span>], names=[<span class="string">&#x27;source&#x27;</span>]).reset_index(level=<span class="string">&#x27;source&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 特征工程</span></span><br><span class="line">all_data[<span class="string">&#x27;Age&#x27;</span>] = all_data.groupby([<span class="string">&#x27;Sex&#x27;</span>, <span class="string">&#x27;Pclass&#x27;</span>])[<span class="string">&#x27;Age&#x27;</span>].transform(<span class="keyword">lambda</span> x: x.fillna(x.median()))</span><br><span class="line">all_data[<span class="string">&#x27;Embarked&#x27;</span>] = all_data[<span class="string">&#x27;Embarked&#x27;</span>].fillna(<span class="string">&#x27;S&#x27;</span>)</span><br><span class="line">all_data[<span class="string">&#x27;Fare&#x27;</span>] = all_data[<span class="string">&#x27;Fare&#x27;</span>].fillna(all_data[<span class="string">&#x27;Fare&#x27;</span>].median())</span><br><span class="line">all_data[<span class="string">&#x27;FamilySize&#x27;</span>] = all_data[<span class="string">&#x27;SibSp&#x27;</span>] + all_data[<span class="string">&#x27;Parch&#x27;</span>] + <span class="number">1</span></span><br><span class="line">all_data[<span class="string">&#x27;IsAlone&#x27;</span>] = (all_data[<span class="string">&#x27;FamilySize&#x27;</span>] == <span class="number">1</span>).astype(<span class="built_in">int</span>)</span><br><span class="line">all_data[<span class="string">&#x27;Title&#x27;</span>] = all_data[<span class="string">&#x27;Name&#x27;</span>].<span class="built_in">str</span>.extract(<span class="string">r&#x27;([A-Za-z]+)\.&#x27;</span>, expand=<span class="literal">False</span>)</span><br><span class="line">rare = [<span class="string">&#x27;Lady&#x27;</span>, <span class="string">&#x27;Countess&#x27;</span>,<span class="string">&#x27;Capt&#x27;</span>, <span class="string">&#x27;Col&#x27;</span>,<span class="string">&#x27;Don&#x27;</span>, <span class="string">&#x27;Dr&#x27;</span>,<span class="string">&#x27;Major&#x27;</span>, <span class="string">&#x27;Rev&#x27;</span>, <span class="string">&#x27;Sir&#x27;</span>, <span class="string">&#x27;Jonkheer&#x27;</span>, <span class="string">&#x27;Dona&#x27;</span>]</span><br><span class="line">all_data[<span class="string">&#x27;Title&#x27;</span>] = all_data[<span class="string">&#x27;Title&#x27;</span>].replace(rare, <span class="string">&#x27;Rare&#x27;</span>)</span><br><span class="line">all_data[<span class="string">&#x27;Title&#x27;</span>] = all_data[<span class="string">&#x27;Title&#x27;</span>].replace(&#123;<span class="string">&#x27;Mlle&#x27;</span>:<span class="string">&#x27;Miss&#x27;</span>, <span class="string">&#x27;Ms&#x27;</span>:<span class="string">&#x27;Miss&#x27;</span>, <span class="string">&#x27;Mme&#x27;</span>:<span class="string">&#x27;Mrs&#x27;</span>&#125;)</span><br><span class="line">all_data[<span class="string">&#x27;AgeBin&#x27;</span>] = pd.cut(all_data[<span class="string">&#x27;Age&#x27;</span>], bins=[<span class="number">0</span>,<span class="number">12</span>,<span class="number">30</span>,<span class="number">50</span>,<span class="number">80</span>], labels=[<span class="string">&#x27;Child&#x27;</span>,<span class="string">&#x27;Young&#x27;</span>,<span class="string">&#x27;Middle&#x27;</span>,<span class="string">&#x27;Elderly&#x27;</span>])</span><br><span class="line">all_data[<span class="string">&#x27;FareBin&#x27;</span>] = pd.qcut(all_data[<span class="string">&#x27;Fare&#x27;</span>], <span class="number">4</span>, labels=[<span class="string">&#x27;Low&#x27;</span>,<span class="string">&#x27;Medium&#x27;</span>,<span class="string">&#x27;High&#x27;</span>,<span class="string">&#x27;VeryHigh&#x27;</span>])</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 编码</span></span><br><span class="line"><span class="keyword">for</span> col <span class="keyword">in</span> [<span class="string">&#x27;Sex&#x27;</span>, <span class="string">&#x27;Title&#x27;</span>, <span class="string">&#x27;AgeBin&#x27;</span>, <span class="string">&#x27;FareBin&#x27;</span>, <span class="string">&#x27;Embarked&#x27;</span>]:</span><br><span class="line">    all_data[col] = LabelEncoder().fit_transform(all_data[col].astype(<span class="built_in">str</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 拆分</span></span><br><span class="line">features = [<span class="string">&#x27;Pclass&#x27;</span>,<span class="string">&#x27;Sex&#x27;</span>,<span class="string">&#x27;Age&#x27;</span>,<span class="string">&#x27;Fare&#x27;</span>,<span class="string">&#x27;Embarked&#x27;</span>,<span class="string">&#x27;FamilySize&#x27;</span>,<span class="string">&#x27;IsAlone&#x27;</span>,<span class="string">&#x27;Title&#x27;</span>,<span class="string">&#x27;AgeBin&#x27;</span>,<span class="string">&#x27;FareBin&#x27;</span>]</span><br><span class="line">X_train = all_data[all_data[<span class="string">&#x27;source&#x27;</span>]==<span class="string">&#x27;train&#x27;</span>][features]</span><br><span class="line">y_train = train[<span class="string">&#x27;Survived&#x27;</span>]</span><br><span class="line">X_test  = all_data[all_data[<span class="string">&#x27;source&#x27;</span>]==<span class="string">&#x27;test&#x27;</span>][features]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 模型</span></span><br><span class="line">model = VotingClassifier([</span><br><span class="line">    (<span class="string">&#x27;lr&#x27;</span>, LogisticRegression(max_iter=<span class="number">1000</span>)),</span><br><span class="line">    (<span class="string">&#x27;rf&#x27;</span>, RandomForestClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">    (<span class="string">&#x27;gb&#x27;</span>, GradientBoostingClassifier(n_estimators=<span class="number">200</span>, random_state=<span class="number">42</span>)),</span><br><span class="line">], voting=<span class="string">&#x27;soft&#x27;</span>)</span><br><span class="line">model.fit(X_train, y_train)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 预测 &amp; 提交</span></span><br><span class="line">preds = model.predict(X_test)</span><br><span class="line">pd.DataFrame(&#123;<span class="string">&#x27;PassengerId&#x27;</span>: ids, <span class="string">&#x27;Survived&#x27;</span>: preds&#125;).to_csv(<span class="string">&#x27;submission.csv&#x27;</span>, index=<span class="literal">False</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;submission.csv created ✅&quot;</span>)</span><br></pre></td></tr></table></figure><p>保存为 <code>titanic.py</code>，下载 Kaggle 数据集到同级目录，<code>python titanic.py</code> 即可得到可提交的 CSV。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Titanic 教会你的不是 YOLO 或 Transformer——<strong>它教的是数据科学的通用流程：</strong></p><ul><li><strong>EDA</strong>：了解数据长什么样，缺失怎么办</li><li><strong>特征工程</strong>：从原始数据中榨取信息（Title 强于 Sex？）</li><li><strong>交叉验证</strong>：别光看训练精度，看泛化能力</li><li><strong>集成</strong>：三个臭皮匠顶一个诸葛亮</li></ul><p>Kaggle 上，新手和高手之间差的就是特征工程和交叉验证之间的那层意识。</p><p><strong>下一步：</strong></p><ul><li>挑战下一步竞赛：House Prices（同类型表格数据，特征工程更复杂）</li><li>或者跳到 Spaceship Titanic（同类型但数据无泄漏，需要更强特征工程）</li><li>学会用 Optuna 自动调参</li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/29/Kaggle%E7%AB%9E%E8%B5%9B%E5%85%A5%E9%97%A8%EF%BC%9ATitanic%E7%94%9F%E5%AD%98%E9%A2%84%E6%B5%8B/</id>
    <link href="https://aijvs.com/2026/07/29/Kaggle%E7%AB%9E%E8%B5%9B%E5%85%A5%E9%97%A8%EF%BC%9ATitanic%E7%94%9F%E5%AD%98%E9%A2%84%E6%B5%8B/"/>
    <published>2026-07-29T01:00:00.000Z</published>
    <summary>手把手完成你的第一个 Kaggle 竞赛项目：数据探索、特征工程、模型集成、提交评分，从 0.77 到 0.82 的完整优化路径。</summary>
    <title>Kaggle 竞赛入门：Titanic 生存预测</title>
    <updated>2026-07-29T01:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="进阶教程" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/"/>
    <category term="实战项目" scheme="https://aijvs.com/tags/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="YOLO" scheme="https://aijvs.com/tags/YOLO/"/>
    <category term="目标检测" scheme="https://aijvs.com/tags/%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B/"/>
    <category term="计算机视觉" scheme="https://aijvs.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"/>
    <category term="Ultralytics" scheme="https://aijvs.com/tags/Ultralytics/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>前面两篇实战，你学会了”这是猫”（分类）和”这是不是手写数字”——但真正现实场景的问题是：<strong>猫在哪？</strong></p><ul><li>自动驾驶：前方有行人和车辆，<strong>它们在哪里？</strong></li><li>安防监控：画面里有没有人闯入？<strong>闯入的人在哪个位置？</strong></li><li>工厂质检：这个零件有没有瑕疵？<strong>瑕疵在哪个区域？</strong></li></ul><p>目标检测 &#x3D; 分类 + 定位。同一张图里，框出所有物体，并说出每个框里是什么。</p><p>YOLO（You Only Look Once）是目前工业界最主流的目标检测框架——<strong>快（实时 30fps+）、准（mAP 追上两阶段检测器）、简单（Ultralytics 封装的 API 只有几行代码）。</strong></p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/">计算机视觉入门：图像处理基础</a></li><li><a href="/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%EF%BC%88CIFAR-10%EF%BC%89/">实战：图像分类（CIFAR-10）</a></li></ul><hr><h2 id="一、环境安装"><a href="#一、环境安装" class="headerlink" title="一、环境安装"></a>一、环境安装</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install ultralytics opencv-python matplotlib</span><br></pre></td></tr></table></figure><p>看，就这么一个包。Ultralytics 团队把训练、验证、导出、推理全部集成到 <code>ultralytics</code> 里了。</p><p>验证安装：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> ultralytics</span><br><span class="line">ultralytics.checks()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Ultralytics 8.3.0 🚀 Python-3.12 torch-2.5.1 CUDA:0 (NVIDIA RTX 4060, 8188MiB)</span><br><span class="line">Setup complete ✅ (8 CPUs, 2 GPUs)</span><br></pre></td></tr></table></figure><hr><h2 id="二、用预训练模型跑推理（5-行代码）"><a href="#二、用预训练模型跑推理（5-行代码）" class="headerlink" title="二、用预训练模型跑推理（5 行代码）"></a>二、用预训练模型跑推理（5 行代码）</h2><p>先感受一下。什么都不用训练，下载一个预训练的 YOLOv8n（n&#x3D;nano，最小最快）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line"><span class="comment"># 下载预训练模型并推理</span></span><br><span class="line">model = YOLO(<span class="string">&#x27;yolov8n.pt&#x27;</span>)  <span class="comment"># 自动下载，6.2MB</span></span><br><span class="line">results = model(<span class="string">&#x27;https://ultralytics.com/images/bus.jpg&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示结果</span></span><br><span class="line">results[<span class="number">0</span>].show()</span><br></pre></td></tr></table></figure><p>会弹出一个窗口，公交车、行人、交通灯全部框好。</p><h3 id="选模型"><a href="#选模型" class="headerlink" title="选模型"></a>选模型</h3><table><thead><tr><th>模型</th><th>参数量</th><th>mAP@50</th><th>速度（GPU）</th><th>下载大小</th></tr></thead><tbody><tr><td>YOLOv8n (nano)</td><td>3.2M</td><td>37.3</td><td><strong>最快</strong></td><td>6.2 MB</td></tr><tr><td>YOLOv8s (small)</td><td>11.2M</td><td>44.9</td><td>快</td><td>22.1 MB</td></tr><tr><td>YOLOv8m (medium)</td><td>25.9M</td><td>50.2</td><td>中等</td><td>51.3 MB</td></tr><tr><td>YOLOv8l (large)</td><td>43.7M</td><td>52.9</td><td>慢</td><td>87.1 MB</td></tr><tr><td>YOLOv8x (xlarge)</td><td>68.2M</td><td><strong>53.9</strong></td><td>最慢</td><td>136.3 MB</td></tr></tbody></table><p><strong>日常用 YOLOv8s</strong>——精度和速度的甜点区。</p><hr><h2 id="三、训练自定义数据集"><a href="#三、训练自定义数据集" class="headerlink" title="三、训练自定义数据集"></a>三、训练自定义数据集</h2><p>以 <strong>口罩检测</strong> 为例——你的任务：从图片中找出谁没戴口罩。</p><h3 id="3-1-数据集格式"><a href="#3-1-数据集格式" class="headerlink" title="3.1 数据集格式"></a>3.1 数据集格式</h3><p>Ultralytics 使用 YOLO 标注格式：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">datasets/</span><br><span class="line">├── images/</span><br><span class="line">│   ├── train/</span><br><span class="line">│   ├── val/</span><br><span class="line">├── labels/</span><br><span class="line">│   ├── train/</span><br><span class="line">│   ├── val/</span><br><span class="line">└── data.yaml</span><br></pre></td></tr></table></figure><p>每张图片对应一个 <code>.txt</code> 标注文件，每行一个目标：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;类别id&gt; &lt;x_center&gt; &lt;y_center&gt; &lt;宽度&gt; &lt;高度&gt;</span><br></pre></td></tr></table></figure><p>归一化到 [0, 1] 的相对坐标。例如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># image.jpg 里有一个人在左上角戴口罩（类别 0），右下角有人没戴（类别 1）</span><br><span class="line">0 0.25 0.30 0.20 0.35</span><br><span class="line">1 0.75 0.70 0.18 0.40</span><br></pre></td></tr></table></figure><h3 id="3-2-准备数据"><a href="#3-2-准备数据" class="headerlink" title="3.2 准备数据"></a>3.2 准备数据</h3><p>你可以标注自己的数据（用 LabelImg &#x2F; Roboflow 标注），也可以直接用公开数据集：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Roboflow 一键下载（需要 API key）</span></span><br><span class="line"><span class="keyword">from</span> roboflow <span class="keyword">import</span> Roboflow</span><br><span class="line">rf = Roboflow(api_key=<span class="string">&quot;YOUR_KEY&quot;</span>)</span><br><span class="line">project = rf.workspace(<span class="string">&quot;roboflow-58fyf&quot;</span>).project(<span class="string">&quot;face-mask-detection&quot;</span>)</span><br><span class="line">dataset = project.version(<span class="number">1</span>).download(<span class="string">&quot;yolov8&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="3-3-训练"><a href="#3-3-训练" class="headerlink" title="3.3 训练"></a>3.3 训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line">model = YOLO(<span class="string">&#x27;yolov8s.pt&#x27;</span>)  <span class="comment"># 从 COCO 预训练权重开始</span></span><br><span class="line"></span><br><span class="line">results = model.train(</span><br><span class="line">    data=<span class="string">&#x27;datasets/face-mask-detection-1/data.yaml&#x27;</span>,</span><br><span class="line">    epochs=<span class="number">50</span>,</span><br><span class="line">    imgsz=<span class="number">640</span>,</span><br><span class="line">    batch=<span class="number">16</span>,</span><br><span class="line">    patience=<span class="number">10</span>,            <span class="comment"># 10 轮没有提升自动停止</span></span><br><span class="line">    lr0=<span class="number">0.01</span>,               <span class="comment"># 初始学习率</span></span><br><span class="line">    augment=<span class="literal">True</span>,           <span class="comment"># 启用数据增强</span></span><br><span class="line">    cache=<span class="literal">True</span>,             <span class="comment"># 缓存图片到 RAM 加速</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>训练过程中，Ultralytics 会实时输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Epoch   GPU_mem   box_loss   cls_loss   dfl_loss   Instances   Size</span><br><span class="line"> 1/50      2.8G      1.462      1.832      1.245         97     640</span><br><span class="line">10/50      2.9G      0.921      0.743      0.986        132     640</span><br><span class="line">20/50      2.9G      0.753      0.512      0.874         84     640</span><br><span class="line">30/50      2.9G      0.642      0.389      0.721        103     640</span><br><span class="line">40/50      2.9G      0.587      0.323      0.668         91     640</span><br><span class="line">50/50      2.9G      0.541      0.287      0.612        105     640</span><br></pre></td></tr></table></figure><p>完成后自动保存到 <code>runs/detect/train</code>。</p><h3 id="3-4-验证"><a href="#3-4-验证" class="headerlink" title="3.4 验证"></a>3.4 验证</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">metrics = model.val()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;mAP@50: <span class="subst">&#123;metrics.box.map50:<span class="number">.3</span>f&#125;</span>&quot;</span>)     <span class="comment"># 平均精度</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;mAP@50-95: <span class="subst">&#123;metrics.box.<span class="built_in">map</span>:<span class="number">.3</span>f&#125;</span>&quot;</span>)    <span class="comment"># 严格版 mAP</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Precision: <span class="subst">&#123;metrics.box.mp:<span class="number">.3</span>f&#125;</span>&quot;</span>)      <span class="comment"># 精确率</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Recall: <span class="subst">&#123;metrics.box.mr:<span class="number">.3</span>f&#125;</span>&quot;</span>)          <span class="comment"># 召回率</span></span><br></pre></td></tr></table></figure><p>预期结果（口罩检测，简单的场景）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mAP@50: 0.923</span><br><span class="line">mAP@50-95: 0.687</span><br><span class="line">Precision: 0.901</span><br><span class="line">Recall: 0.888</span><br></pre></td></tr></table></figure><hr><h2 id="四、实时摄像头检测"><a href="#四、实时摄像头检测" class="headerlink" title="四、实时摄像头检测"></a>四、实时摄像头检测</h2><p>训练好的模型可以直接接摄像头：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line">model = YOLO(<span class="string">&#x27;runs/detect/train/weights/best.pt&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 调用摄像头</span></span><br><span class="line">results = model.predict(source=<span class="number">0</span>, show=<span class="literal">True</span>, conf=<span class="number">0.5</span>)</span><br></pre></td></tr></table></figure><p>或者对视频文件做推理：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">results = model.predict(</span><br><span class="line">    source=<span class="string">&#x27;test_video.mp4&#x27;</span>,</span><br><span class="line">    save=<span class="literal">True</span>,              <span class="comment"># 保存标注后的视频</span></span><br><span class="line">    conf=<span class="number">0.5</span>,               <span class="comment"># 置信度阈值</span></span><br><span class="line">    iou=<span class="number">0.5</span>,                <span class="comment"># NMS IoU 阈值（重叠度高时保留哪个框）</span></span><br><span class="line">    line_width=<span class="number">2</span>,</span><br><span class="line">    show_labels=<span class="literal">True</span>,</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h3 id="关键参数调优"><a href="#关键参数调优" class="headerlink" title="关键参数调优"></a>关键参数调优</h3><ul><li><strong>conf（置信度阈值）</strong>：默认 0.25。场景里干扰多就调高（0.5），目标太小就调低（0.1）</li><li><strong>iou（NMS 阈值）</strong>：默认 0.7。调低→同一目标不会出现多个框，但可能漏检</li></ul><p>实际生产中的调法：先跑 100 张测试图，看漏检&#x2F;误检的比例，再调这两个参数。</p><hr><h2 id="五、部署到边缘设备"><a href="#五、部署到边缘设备" class="headerlink" title="五、部署到边缘设备"></a>五、部署到边缘设备</h2><p>YOLOv8 支持导出多种格式，覆盖从服务器到手机的部署场景：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">model = YOLO(<span class="string">&#x27;runs/detect/train/weights/best.pt&#x27;</span>)</span><br><span class="line"></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;onnx&#x27;</span>)           <span class="comment"># ONNX：通用格式，可部署到任何推理框架</span></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;tflite&#x27;</span>)         <span class="comment"># TFLite：Android / 树莓派</span></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;ncnn&#x27;</span>)           <span class="comment"># NCNN：手机端（骁龙/联发科NPU加速）</span></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;tensorrt&#x27;</span>)       <span class="comment"># TensorRT：NVIDIA GPU 加速（3-5倍提速）</span></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;openvino&#x27;</span>)       <span class="comment"># OpenVINO：Intel CPU / 神经计算棒</span></span><br></pre></td></tr></table></figure><p><strong>实际速度对比</strong>（口罩检测，640×640 输入）：</p><table><thead><tr><th>导出格式</th><th>设备</th><th>推理速度</th><th>部署难度</th></tr></thead><tbody><tr><td>PyTorch</td><td>RTX 4060</td><td>2ms</td><td>-</td></tr><tr><td>TensorRT</td><td>RTX 4060</td><td><strong>0.8ms</strong></td><td>中等</td></tr><tr><td>ONNX</td><td>CPU</td><td>15ms</td><td>简单</td></tr><tr><td>ONNX</td><td>Jetson Nano</td><td>40ms</td><td>中等</td></tr><tr><td>TFLite</td><td>树莓派 4B</td><td>120ms</td><td>简单</td></tr><tr><td>NCNN</td><td>骁龙 8 Gen3</td><td>8ms</td><td>中等</td></tr></tbody></table><hr><h2 id="六、常见问题"><a href="#六、常见问题" class="headerlink" title="六、常见问题"></a>六、常见问题</h2><h3 id="6-1-小目标检测不好怎么办"><a href="#6-1-小目标检测不好怎么办" class="headerlink" title="6.1 小目标检测不好怎么办"></a>6.1 小目标检测不好怎么办</h3><p>YOLO 默认 640×640 输入。如果你要检测口罩、车牌、文字这种小目标：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">model.train(imgsz=<span class="number">1280</span>, ...)  <span class="comment"># 更大的输入尺寸 → 小目标特征更明显</span></span><br></pre></td></tr></table></figure><p>但注意：<strong>imgsz×2 → 推理时间 ×4</strong>（分辨率平方成正比）。</p><h3 id="6-2-类别不平衡"><a href="#6-2-类别不平衡" class="headerlink" title="6.2 类别不平衡"></a>6.2 类别不平衡</h3><p>某些类别的样本多（戴了口罩），某些少（没戴口罩）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">model.train(</span><br><span class="line">    cls_pw=<span class="number">1.0</span>,          <span class="comment"># 类别权重，&gt;1 增加少样本类别的 loss</span></span><br><span class="line">    ...</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>或者在数据层面，对少样本类别多做数据增强。</p><h3 id="6-3-隐私场景不能把数据上传到云端"><a href="#6-3-隐私场景不能把数据上传到云端" class="headerlink" title="6.3 隐私场景不能把数据上传到云端"></a>6.3 隐私场景不能把数据上传到云端</h3><p>YOLO 全本地部署。下载模型后完全离线运行，不需要联网。</p><hr><h2 id="七、完整训练代码"><a href="#七、完整训练代码" class="headerlink" title="七、完整训练代码"></a>七、完整训练代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;yolo_train.py - YOLOv8 目标检测训练&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">from</span> ultralytics <span class="keyword">import</span> YOLO</span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 加载预训练模型</span></span><br><span class="line">model = YOLO(<span class="string">&#x27;yolov8s.pt&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 训练</span></span><br><span class="line">results = model.train(</span><br><span class="line">    data=<span class="string">&#x27;datasets/face-mask-detection-1/data.yaml&#x27;</span>,</span><br><span class="line">    epochs=<span class="number">50</span>,</span><br><span class="line">    imgsz=<span class="number">640</span>,</span><br><span class="line">    batch=<span class="number">16</span>,</span><br><span class="line">    patience=<span class="number">10</span>,</span><br><span class="line">    lr0=<span class="number">0.01</span>,</span><br><span class="line">    augment=<span class="literal">True</span>,</span><br><span class="line">    cache=<span class="literal">True</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 验证</span></span><br><span class="line">metrics = model.val()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Precision: <span class="subst">&#123;metrics.box.mp:<span class="number">.3</span>f&#125;</span>&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Recall: <span class="subst">&#123;metrics.box.mr:<span class="number">.3</span>f&#125;</span>&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;mAP@50: <span class="subst">&#123;metrics.box.map50:<span class="number">.3</span>f&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 导出</span></span><br><span class="line">model.export(<span class="built_in">format</span>=<span class="string">&#x27;onnx&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 测试推理</span></span><br><span class="line">results = model.predict(</span><br><span class="line">    source=<span class="string">&#x27;test_images/&#x27;</span>,</span><br><span class="line">    save=<span class="literal">True</span>,</span><br><span class="line">    conf=<span class="number">0.5</span>,</span><br><span class="line">    iou=<span class="number">0.5</span>,</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>把这 20 行代码放到有 GPU 的机器上，配置好数据集路径，直接 <code>python yolo_train.py</code> 就能跑。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>目标检测跟图像分类的区别总结成一句话：<strong>分类说”有什么”，检测说”有什么+在哪”。</strong></p><ul><li>YOLO 家族是事实上的工业标准——30fps 以上实时推理</li><li>Ultralytics 把训练&#x2F;验证&#x2F;导出&#x2F;推理集成在一个包，20 行代码落地</li><li>导出格式覆盖全平台（GPU&#x2F;CPU&#x2F;手机&#x2F;嵌入式），一套代码到处跑</li></ul><p><strong>进阶路线：</strong></p><ul><li>COCO 官方基准测试跑一遍，看你的模型跟 SOTA 差多少</li><li>挑战更难的场景：夜间检测、遮挡检测、密集场景</li><li>尝试 YOLOv8-seg（实例分割），框变成蒙版，更精准</li><li>学习 ByteTrack，把视频帧中的检测框关联成轨迹</li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/29/%E5%AE%9E%E6%88%98%EF%BC%9A%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%EF%BC%88YOLOv8%EF%BC%89/</id>
    <link href="https://aijvs.com/2026/07/29/%E5%AE%9E%E6%88%98%EF%BC%9A%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%EF%BC%88YOLOv8%EF%BC%89/"/>
    <published>2026-07-29T00:00:00.000Z</published>
    <summary>用 YOLOv8 实现实时目标检测：训练自定义数据集、调优超参数、部署到摄像头实时检测，支持 CPU/GPU/边缘设备。</summary>
    <title>实战：目标检测（YOLOv8）</title>
    <updated>2026-07-29T00:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="NLP" scheme="https://aijvs.com/tags/NLP/"/>
    <category term="自然语言处理" scheme="https://aijvs.com/tags/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/"/>
    <category term="PyTorch" scheme="https://aijvs.com/tags/PyTorch/"/>
    <category term="进阶教程" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/"/>
    <category term="情感分析" scheme="https://aijvs.com/tags/%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90/"/>
    <category term="LSTM" scheme="https://aijvs.com/tags/LSTM/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>给一条评论，判断是好评还是差评——就这么简单的一个二分类问题。</p><p>但真正动手做的时候，你会发现：</p><ul><li>关键词匹配：”这个产品不错”→ 好评，”质量很差”→ 差评 → 碰上”<strong>不</strong>错”就挂了</li><li>标点符号：”好吃！”→ 好评，”好吃？”→ 饿了吗？</li></ul><p><strong>语言的复杂性，让”简单”的二分类没那么简单。</strong></p><p>这篇带你完整走一遍：从最简单的词袋模型，到 LSTM 序列模型，再到 BERT 预训练模型——看看每一代模型到底强在哪。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/NLP%E5%85%A5%E9%97%A8%EF%BC%9A%E6%96%87%E6%9C%AC%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E8%AF%8D%E5%90%91%E9%87%8F/">NLP 入门：文本预处理与词向量</a></li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li></ul><hr><h2 id="一、数据准备"><a href="#一、数据准备" class="headerlink" title="一、数据准备"></a>一、数据准备</h2><p>用 IMDB 电影评论数据集（25,000 条训练 + 25,000 条测试，二分类）。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> Dataset, DataLoader</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> Counter</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line"><span class="comment"># 用 torchtext 加载</span></span><br><span class="line"><span class="keyword">from</span> torchtext.datasets <span class="keyword">import</span> IMDB</span><br><span class="line"></span><br><span class="line">train_iter, test_iter = IMDB(split=(<span class="string">&#x27;train&#x27;</span>, <span class="string">&#x27;test&#x27;</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 看一眼数据</span></span><br><span class="line"><span class="keyword">for</span> i, (label, text) <span class="keyword">in</span> <span class="built_in">enumerate</span>(train_iter):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;标签: <span class="subst">&#123;<span class="string">&#x27;正面&#x27;</span> <span class="keyword">if</span> label == <span class="number">2</span> <span class="keyword">else</span> <span class="string">&#x27;负面&#x27;</span>&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;文本: <span class="subst">&#123;text[:<span class="number">200</span>]&#125;</span>...&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> i == <span class="number">0</span>: <span class="keyword">break</span></span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">标签: 正面</span><br><span class="line">文本: This film is just brilliant. The acting is superb and the story ...</span><br></pre></td></tr></table></figure><hr><h2 id="二、方案一：词袋模型（Bag-of-Words）"><a href="#二、方案一：词袋模型（Bag-of-Words）" class="headerlink" title="二、方案一：词袋模型（Bag of Words）"></a>二、方案一：词袋模型（Bag of Words）</h2><h3 id="2-1-构建词表"><a href="#2-1-构建词表" class="headerlink" title="2.1 构建词表"></a>2.1 构建词表</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">tokenize</span>(<span class="params">text</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;简单分词：转小写，去标点&quot;&quot;&quot;</span></span><br><span class="line">    text = text.lower()</span><br><span class="line">    text = re.sub(<span class="string">r&#x27;[^a-z\s]&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line">    <span class="keyword">return</span> text.split()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 统计词频，保留最常见的 10,000 个词</span></span><br><span class="line">counter = Counter()</span><br><span class="line"><span class="keyword">for</span> label, text <span class="keyword">in</span> train_iter:</span><br><span class="line">    counter.update(tokenize(text))</span><br><span class="line"></span><br><span class="line">vocab = [<span class="string">&#x27;&lt;PAD&gt;&#x27;</span>, <span class="string">&#x27;&lt;UNK&gt;&#x27;</span>] + [word <span class="keyword">for</span> word, _ <span class="keyword">in</span> counter.most_common(<span class="number">10000</span>)]</span><br><span class="line">word2idx = &#123;word: i <span class="keyword">for</span> i, word <span class="keyword">in</span> <span class="built_in">enumerate</span>(vocab)&#125;</span><br></pre></td></tr></table></figure><h3 id="2-2-文本转向量"><a href="#2-2-文本转向量" class="headerlink" title="2.2 文本转向量"></a>2.2 文本转向量</h3><p>词袋的意思就是：<strong>统计每个词出现了多少次</strong>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">bow_vectorize</span>(<span class="params">text, vocab_size</span>):</span><br><span class="line">    vec = np.zeros(vocab_size, dtype=np.float32)</span><br><span class="line">    <span class="keyword">for</span> word <span class="keyword">in</span> tokenize(text):</span><br><span class="line">        idx = word2idx.get(word, <span class="number">1</span>)  <span class="comment"># 1 = &lt;UNK&gt;</span></span><br><span class="line">        vec[idx] += <span class="number">1</span></span><br><span class="line">    <span class="keyword">return</span> vec</span><br></pre></td></tr></table></figure><h3 id="2-3-模型与训练"><a href="#2-3-模型与训练" class="headerlink" title="2.3 模型与训练"></a>2.3 模型与训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">BOWClassifier</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, vocab_size, hidden=<span class="number">128</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.fc1 = nn.Linear(vocab_size, hidden)</span><br><span class="line">        <span class="variable language_">self</span>.fc2 = nn.Linear(hidden, <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc1(x))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc2(x)</span><br></pre></td></tr></table></figure><p>受限于篇幅，这里不展开完整训练循环。核心结论：</p><table><thead><tr><th>方案</th><th>测试精度</th><th>训练时间</th></tr></thead><tbody><tr><td>词袋 + 逻辑回归</td><td><strong>~68%</strong></td><td>快（秒级）</td></tr><tr><td>词袋 + 神经网络</td><td><strong>~72%</strong></td><td>中等（分钟级）</td></tr></tbody></table><p>68% 是什么概念？比瞎猜（50%）好一点，但离可用还很远。</p><p><strong>问题出在哪？</strong> 词袋丢了词序——“not good”和”good”在 BoW 眼里几乎一模一样。</p><hr><h2 id="三、方案二：LSTM-序列模型"><a href="#三、方案二：LSTM-序列模型" class="headerlink" title="三、方案二：LSTM 序列模型"></a>三、方案二：LSTM 序列模型</h2><p>LSTM 的核心能力：<strong>记住上下文</strong>。</p><p>“这部电影不怎么样，但比上一部好”——LSTM 能感受到从消极到积极的转折。BoW 只能看到一堆词。</p><h3 id="3-1-文本转索引序列"><a href="#3-1-文本转索引序列" class="headerlink" title="3.1 文本转索引序列"></a>3.1 文本转索引序列</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">IMDBDataset</span>(<span class="title class_ inherited__">Dataset</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, data_iter, word2idx, max_len=<span class="number">200</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.data = []</span><br><span class="line">        <span class="keyword">for</span> label, text <span class="keyword">in</span> data_iter:</span><br><span class="line">            tokens = tokenize(text)</span><br><span class="line">            indices = [word2idx.get(w, <span class="number">1</span>) <span class="keyword">for</span> w <span class="keyword">in</span> tokens[:max_len]]</span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">len</span>(indices) &lt; max_len:</span><br><span class="line">                indices += [<span class="number">0</span>] * (max_len - <span class="built_in">len</span>(indices))</span><br><span class="line">            <span class="variable language_">self</span>.data.append((torch.tensor(indices, dtype=torch.long),</span><br><span class="line">                              torch.tensor(<span class="number">1</span> <span class="keyword">if</span> label == <span class="number">2</span> <span class="keyword">else</span> <span class="number">0</span>, dtype=torch.long)))</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__len__</span>(<span class="params">self</span>): <span class="keyword">return</span> <span class="built_in">len</span>(<span class="variable language_">self</span>.data)</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getitem__</span>(<span class="params">self, i</span>): <span class="keyword">return</span> <span class="variable language_">self</span>.data[i]</span><br><span class="line"></span><br><span class="line">train_dataset = IMDBDataset(train_iter, word2idx)</span><br><span class="line">train_loader = DataLoader(train_dataset, batch_size=<span class="number">64</span>, shuffle=<span class="literal">True</span>)</span><br></pre></td></tr></table></figure><h3 id="3-2-LSTM-模型"><a href="#3-2-LSTM-模型" class="headerlink" title="3.2 LSTM 模型"></a>3.2 LSTM 模型</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LSTMClassifier</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, vocab_size, embed_dim=<span class="number">100</span>, hidden_dim=<span class="number">128</span>, num_layers=<span class="number">2</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=<span class="number">0</span>)</span><br><span class="line">        <span class="variable language_">self</span>.lstm = nn.LSTM(embed_dim, hidden_dim, num_layers,</span><br><span class="line">                           batch_first=<span class="literal">True</span>, dropout=<span class="number">0.3</span>, bidirectional=<span class="literal">True</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc = nn.Linear(hidden_dim * <span class="number">2</span>, <span class="number">2</span>)  <span class="comment"># *2 因为双向</span></span><br><span class="line">        <span class="variable language_">self</span>.dropout = nn.Dropout(<span class="number">0.3</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.embedding(x)</span><br><span class="line">        _, (hidden, _) = <span class="variable language_">self</span>.lstm(x)</span><br><span class="line">        h = torch.cat((hidden[-<span class="number">2</span>], hidden[-<span class="number">1</span>]), dim=<span class="number">1</span>)</span><br><span class="line">        h = <span class="variable language_">self</span>.dropout(torch.relu(h))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc(h)</span><br></pre></td></tr></table></figure><p>关键设计选择：</p><ul><li><strong>双向 LSTM</strong>：不仅看左边的词，还看右边的词——“这种质量的产品，我给不<strong>好评</strong>“</li><li><strong>Embedding 层</strong>：把离散的词 ID 映射成稠密向量，相似含义的词向量距离更近</li><li><strong>Dropout&#x3D;0.3</strong>：防止过拟合</li></ul><h3 id="3-3-训练"><a href="#3-3-训练" class="headerlink" title="3.3 训练"></a>3.3 训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">model = LSTMClassifier(<span class="built_in">len</span>(vocab)).to(device)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line">optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">6</span>):</span><br><span class="line">    model.train()</span><br><span class="line">    total_loss = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> inputs, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">        inputs, labels = inputs.to(device), labels.to(device)</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        outputs = model(inputs)</span><br><span class="line">        loss = criterion(outputs, labels)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        total_loss += loss.item()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: loss=<span class="subst">&#123;total_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期结果：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Epoch 1: loss=0.5472</span><br><span class="line">Epoch 2: loss=0.3228</span><br><span class="line">Epoch 3: loss=0.2183</span><br><span class="line">Epoch 4: loss=0.1531</span><br><span class="line">Epoch 5: loss=0.1127   # 测试集精度 ~86%</span><br></pre></td></tr></table></figure><p><strong>86%</strong>，比 BoW 涨了 14 个点。</p><p><strong>但 LSTM 有一个上限问题：</strong> 它逐词处理，长距离依赖仍然吃力。”虽然……但是……可惜……” 这种句式，LSTM 只能记住最近的几个转折。</p><hr><h2 id="四、方案三：BERT-预训练模型"><a href="#四、方案三：BERT-预训练模型" class="headerlink" title="四、方案三：BERT 预训练模型"></a>四、方案三：BERT 预训练模型</h2><p>BERT 最大的贡献是<strong>双向上下文</strong>——“银行”在”去银行取钱”和”中央银行政策”里有完全不同的含义，BERT 能区分。</p><h3 id="4-1-加载预训练-BERT"><a href="#4-1-加载预训练-BERT" class="headerlink" title="4.1 加载预训练 BERT"></a>4.1 加载预训练 BERT</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span> BertTokenizer, BertForSequenceClassification</span><br><span class="line"></span><br><span class="line">model_name = <span class="string">&#x27;bert-base-uncased&#x27;</span></span><br><span class="line">tokenizer = BertTokenizer.from_pretrained(model_name)</span><br><span class="line">model = BertForSequenceClassification.from_pretrained(model_name, num_labels=<span class="number">2</span>)</span><br></pre></td></tr></table></figure><p>就两行。297M 参数，预训练在 3.3B 词上。你只需要在 IMDB 上微调。</p><h3 id="4-2-数据加载"><a href="#4-2-数据加载" class="headerlink" title="4.2 数据加载"></a>4.2 数据加载</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">BERTDataset</span>(<span class="title class_ inherited__">Dataset</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, data_iter, tokenizer, max_len=<span class="number">256</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.input_ids = []</span><br><span class="line">        <span class="variable language_">self</span>.attention_masks = []</span><br><span class="line">        <span class="variable language_">self</span>.labels = []</span><br><span class="line">        <span class="keyword">for</span> label, text <span class="keyword">in</span> data_iter:</span><br><span class="line">            encoded = tokenizer(</span><br><span class="line">                text,</span><br><span class="line">                truncation=<span class="literal">True</span>,</span><br><span class="line">                padding=<span class="string">&#x27;max_length&#x27;</span>,</span><br><span class="line">                max_length=max_len,</span><br><span class="line">                return_tensors=<span class="string">&#x27;pt&#x27;</span></span><br><span class="line">            )</span><br><span class="line">            <span class="variable language_">self</span>.input_ids.append(encoded[<span class="string">&#x27;input_ids&#x27;</span>][<span class="number">0</span>])</span><br><span class="line">            <span class="variable language_">self</span>.attention_masks.append(encoded[<span class="string">&#x27;attention_mask&#x27;</span>][<span class="number">0</span>])</span><br><span class="line">            <span class="variable language_">self</span>.labels.append(<span class="number">1</span> <span class="keyword">if</span> label == <span class="number">2</span> <span class="keyword">else</span> <span class="number">0</span>)</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__len__</span>(<span class="params">self</span>): <span class="keyword">return</span> <span class="built_in">len</span>(<span class="variable language_">self</span>.input_ids)</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getitem__</span>(<span class="params">self, i</span>):</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="string">&#x27;input_ids&#x27;</span>: <span class="variable language_">self</span>.input_ids[i],</span><br><span class="line">            <span class="string">&#x27;attention_mask&#x27;</span>: <span class="variable language_">self</span>.attention_masks[i],</span><br><span class="line">            <span class="string">&#x27;labels&#x27;</span>: torch.tensor(<span class="variable language_">self</span>.labels[i], dtype=torch.long)</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">train_dataset = BERTDataset(train_iter, tokenizer)</span><br><span class="line">train_loader = DataLoader(train_dataset, batch_size=<span class="number">16</span>, shuffle=<span class="literal">True</span>)</span><br></pre></td></tr></table></figure><p><strong>注意 batch_size&#x3D;16。</strong> BERT 有 3 亿参数，显存吃得很厉害——GPU 至少 8GB 才能跑。</p><h3 id="4-3-微调"><a href="#4-3-微调" class="headerlink" title="4.3 微调"></a>4.3 微调</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span> AdamW</span><br><span class="line"></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span>)</span><br><span class="line">model.to(device)</span><br><span class="line">optimizer = AdamW(model.parameters(), lr=<span class="number">2e-5</span>)  <span class="comment"># 必须用很小的学习率</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">4</span>):  <span class="comment"># BERT 微调 3 轮就能收敛</span></span><br><span class="line">    model.train()</span><br><span class="line">    total_loss = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> batch <span class="keyword">in</span> train_loader:</span><br><span class="line">        batch = &#123;k: v.to(device) <span class="keyword">for</span> k, v <span class="keyword">in</span> batch.items()&#125;</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        outputs = model(**batch)</span><br><span class="line">        loss = outputs.loss</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        total_loss += loss.item()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: loss=<span class="subst">&#123;total_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期精度：<strong>93%+</strong>。</p><hr><h2 id="五、三方案对比"><a href="#五、三方案对比" class="headerlink" title="五、三方案对比"></a>五、三方案对比</h2><table><thead><tr><th>方案</th><th>参数量</th><th>精度</th><th>训练时间（GPU）</th><th>训练时间（CPU）</th></tr></thead><tbody><tr><td>词袋 + NN</td><td>~1.2M</td><td>68-72%</td><td>1min</td><td>5min</td></tr><tr><td>双向 LSTM</td><td>~3.0M</td><td>~86%</td><td>15min</td><td>2h</td></tr><tr><td>BERT 微调</td><td>297M</td><td><strong>~93%</strong></td><td>30min</td><td>❌ 基本不可行</td></tr></tbody></table><h3 id="选型建议"><a href="#选型建议" class="headerlink" title="选型建议"></a>选型建议</h3><ul><li><strong>能接受 70% 精度？</strong> → 词袋模型 + 正则化（适合资源极度受限的场景）</li><li><strong>需要 85%+ 并且有 GPU？</strong> → LSTM 是性价比之王</li><li><strong>必须 90%+ 并且有 GPU？</strong> → BERT 或它的蒸馏版（DistilBERT，一半大小，95% 效果）</li></ul><h3 id="为什么要学前两个方案？"><a href="#为什么要学前两个方案？" class="headerlink" title="为什么要学前两个方案？"></a>为什么要学前两个方案？</h3><p>BERT 虽然强，但你控制不了它——遇到 OOV 词怎么处理？长文本拆分策略？领域迁移要怎么继续预训练？不懂底层原理，你连 BERT 的 tokenizer 参数都调不明白。</p><hr><h2 id="六、完整代码"><a href="#六、完整代码" class="headerlink" title="六、完整代码"></a>六、完整代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;sentiment_lstm.py - LSTM 情感分析&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> torch, re</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> Dataset, DataLoader</span><br><span class="line"><span class="keyword">from</span> torchtext.datasets <span class="keyword">import</span> IMDB</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> Counter</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">tokenize</span>(<span class="params">text</span>):</span><br><span class="line">    text = text.lower()</span><br><span class="line">    text = re.sub(<span class="string">r&#x27;[^a-z\s]&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line">    <span class="keyword">return</span> text.split()</span><br><span class="line"></span><br><span class="line">counter = Counter()</span><br><span class="line"><span class="keyword">for</span> label, text <span class="keyword">in</span> IMDB(split=<span class="string">&#x27;train&#x27;</span>):</span><br><span class="line">    counter.update(tokenize(text))</span><br><span class="line">vocab = [<span class="string">&#x27;&lt;PAD&gt;&#x27;</span>, <span class="string">&#x27;&lt;UNK&gt;&#x27;</span>] + [w <span class="keyword">for</span> w, _ <span class="keyword">in</span> counter.most_common(<span class="number">10000</span>)]</span><br><span class="line">word2idx = &#123;w: i <span class="keyword">for</span> i, w <span class="keyword">in</span> <span class="built_in">enumerate</span>(vocab)&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">IMDBDataset</span>(<span class="title class_ inherited__">Dataset</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, split, word2idx, max_len=<span class="number">200</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.data = []</span><br><span class="line">        <span class="keyword">for</span> label, text <span class="keyword">in</span> IMDB(split=split):</span><br><span class="line">            indices = [word2idx.get(w, <span class="number">1</span>) <span class="keyword">for</span> w <span class="keyword">in</span> tokenize(text)[:max_len]]</span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">len</span>(indices) &lt; max_len:</span><br><span class="line">                indices += [<span class="number">0</span>] * (max_len - <span class="built_in">len</span>(indices))</span><br><span class="line">            <span class="variable language_">self</span>.data.append((torch.tensor(indices, dtype=torch.long),</span><br><span class="line">                              torch.tensor(<span class="number">1</span> <span class="keyword">if</span> label == <span class="number">2</span> <span class="keyword">else</span> <span class="number">0</span>, dtype=torch.long)))</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__len__</span>(<span class="params">self</span>): <span class="keyword">return</span> <span class="built_in">len</span>(<span class="variable language_">self</span>.data)</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getitem__</span>(<span class="params">self, i</span>): <span class="keyword">return</span> <span class="variable language_">self</span>.data[i]</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(IMDBDataset(<span class="string">&#x27;train&#x27;</span>, word2idx), batch_size=<span class="number">64</span>, shuffle=<span class="literal">True</span>)</span><br><span class="line">test_loader  = DataLoader(IMDBDataset(<span class="string">&#x27;test&#x27;</span>, word2idx), batch_size=<span class="number">256</span>, shuffle=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LSTMClassifier</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, vocab_size, embed=<span class="number">100</span>, hidden=<span class="number">128</span>, num_layers=<span class="number">2</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.embedding = nn.Embedding(vocab_size, embed, padding_idx=<span class="number">0</span>)</span><br><span class="line">        <span class="variable language_">self</span>.lstm = nn.LSTM(embed, hidden, num_layers, batch_first=<span class="literal">True</span>,</span><br><span class="line">                           dropout=<span class="number">0.3</span>, bidirectional=<span class="literal">True</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc = nn.Linear(hidden*<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line">        <span class="variable language_">self</span>.dropout = nn.Dropout(<span class="number">0.3</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.embedding(x)</span><br><span class="line">        _, (h, _) = <span class="variable language_">self</span>.lstm(x)</span><br><span class="line">        h = torch.cat((h[-<span class="number">2</span>], h[-<span class="number">1</span>]), dim=<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc(<span class="variable language_">self</span>.dropout(torch.relu(h)))</span><br><span class="line"></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">model = LSTMClassifier(<span class="built_in">len</span>(vocab)).to(device)</span><br><span class="line">optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">6</span>):</span><br><span class="line">    model.train()</span><br><span class="line">    total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> inputs, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">        inputs, labels = inputs.to(device), labels.to(device)</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        criterion(model(inputs), labels).backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        total += criterion(model(inputs), labels).item()</span><br><span class="line"></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    correct = <span class="built_in">sum</span>((model(x.to(device)).argmax(<span class="number">1</span>) == y.to(device)).<span class="built_in">sum</span>().item()</span><br><span class="line">                  <span class="keyword">for</span> x, y <span class="keyword">in</span> test_loader)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: acc=<span class="subst">&#123;correct/<span class="number">25000</span>:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>保存为 <code>sentiment_lstm.py</code> 直接跑（需要先 <code>pip install torchtext</code>）。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>情感分析三类方案准确度跨度 <strong>68% → 86% → 93%</strong>，每个增长台阶的背后都是一个核心技术创新：</p><ul><li><strong>词袋 → LSTM</strong>：从”丢词序”到”记住上下文”（+14%）</li><li><strong>LSTM → BERT</strong>：从”单向记忆”到”预训练大模型”（+7%）</li></ul><p>后面的增长会更难。96% 往上需要对抗生成、领域自适应、多模态融合——这就是顶会论文的方向了。</p><p><strong>建议行动：</strong></p><ol><li>在 Kaggle 上跑 BERT 微调，完整体验训练流程</li><li>用你自己的产品评论跑一遍，看看精度变化</li><li>尝试 DistilBERT，看速度和精度的 trade-off</li></ol>]]>
    </content>
    <id>https://aijvs.com/2026/07/28/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90%E7%B3%BB%E7%BB%9F/</id>
    <link href="https://aijvs.com/2026/07/28/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90%E7%B3%BB%E7%BB%9F/"/>
    <published>2026-07-28T23:00:00.000Z</published>
    <summary>从零构建中文/英文情感分析系统，对比词袋模型、LSTM 和 BERT 三代的精度差距：68% → 86% → 93%。</summary>
    <title>实战：情感分析系统</title>
    <updated>2026-07-28T23:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="PyTorch" scheme="https://aijvs.com/tags/PyTorch/"/>
    <category term="CIFAR-10" scheme="https://aijvs.com/tags/CIFAR-10/"/>
    <category term="图像分类" scheme="https://aijvs.com/tags/%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB/"/>
    <category term="进阶教程" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/"/>
    <category term="数据增强" scheme="https://aijvs.com/tags/%E6%95%B0%E6%8D%AE%E5%A2%9E%E5%BC%BA/"/>
    <category term="迁移学习" scheme="https://aijvs.com/tags/%E8%BF%81%E7%A7%BB%E5%AD%A6%E4%B9%A0/"/>
    <category term="实战项目" scheme="https://aijvs.com/tags/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>MNIST 的准确率刷到 99% 了，然后呢？</p><p>你换了张真实照片——模糊的、带噪点的、背景花里胡哨的——CNN 直接掉到 70%。</p><p><strong>不是你模型不行，是 MNIST 太简单了。</strong></p><p>CIFAR-10 就是下一个台阶：32×32 彩色图片，10 个类别，真正的”AI 能不能分清猫和狗”。</p><ul><li>训练集：50,000 张</li><li>测试集：10,000 张</li><li>彩色（3 通道 RGB），32×32 像素</li><li>10 类：飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车</li></ul><p>跟 MNIST 的本质区别：<strong>颜色 + 纹理 + 形状才是特征，纯像素不够。</strong></p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB%EF%BC%88MNIST%EF%BC%89/">实战：手写数字识别（MNIST）</a></li><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN 卷积神经网络</a></li></ul><hr><h2 id="一、基线-CNN"><a href="#一、基线-CNN" class="headerlink" title="一、基线 CNN"></a>一、基线 CNN</h2><p>先拿一个比 MNIST 那篇更深的 CNN，看 CIFAR-10 的难度。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> datasets, transforms</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据加载（无增强版）</span></span><br><span class="line">transform = transforms.Compose([</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(mean=[<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>],</span><br><span class="line">                         std=[<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>])</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">train_data = datasets.CIFAR10(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>,  download=<span class="literal">True</span>, transform=transform)</span><br><span class="line">test_data  = datasets.CIFAR10(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">False</span>, download=<span class="literal">True</span>, transform=transform)</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(train_data, batch_size=<span class="number">128</span>, shuffle=<span class="literal">True</span>, num_workers=<span class="number">2</span>)</span><br><span class="line">test_loader  = DataLoader(test_data,  batch_size=<span class="number">256</span>, shuffle=<span class="literal">False</span>, num_workers=<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BasicCNN</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;3 层卷积 + 2 层全连接&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = nn.Conv2d(<span class="number">3</span>, <span class="number">64</span>, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.bn1   = nn.BatchNorm2d(<span class="number">64</span>)</span><br><span class="line">        <span class="variable language_">self</span>.conv2 = nn.Conv2d(<span class="number">64</span>, <span class="number">128</span>, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.bn2   = nn.BatchNorm2d(<span class="number">128</span>)</span><br><span class="line">        <span class="variable language_">self</span>.conv3 = nn.Conv2d(<span class="number">128</span>, <span class="number">256</span>, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.bn3   = nn.BatchNorm2d(<span class="number">256</span>)</span><br><span class="line">        <span class="variable language_">self</span>.pool  = nn.MaxPool2d(<span class="number">2</span>, <span class="number">2</span>)     <span class="comment"># 32→16→8→4</span></span><br><span class="line">        <span class="variable language_">self</span>.fc1   = nn.Linear(<span class="number">256</span> * <span class="number">4</span> * <span class="number">4</span>, <span class="number">512</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc2   = nn.Linear(<span class="number">512</span>, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.bn1(<span class="variable language_">self</span>.conv1(x))))  <span class="comment"># 32→16</span></span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.bn2(<span class="variable language_">self</span>.conv2(x))))  <span class="comment"># 16→8</span></span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.bn3(<span class="variable language_">self</span>.conv3(x))))  <span class="comment"># 8→4</span></span><br><span class="line">        x = x.view(x.size(<span class="number">0</span>), -<span class="number">1</span>)</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc1(x))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc2(x)</span><br></pre></td></tr></table></figure><p>训练代码跟 MNIST 实测那篇一样，只是加了两个新东西：</p><p><strong>BatchNorm2d（批归一化）</strong>：每一层输出都做归一化，加速收敛、减少过拟合。好消息：加了 BatchNorm 之后，你可以用更大的学习率。</p><p><strong>num_workers&#x3D;2</strong>：用 2 个进程预加载数据，GPU 不会被 CPU 拖慢。训 CPU 时可以关掉（&#x3D;0）。</p><p>跑 20 轮：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">train</span>():</span><br><span class="line">    device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">    model = BasicCNN().to(device)</span><br><span class="line">    criterion = nn.CrossEntropyLoss()</span><br><span class="line">    optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line">    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=<span class="number">20</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">21</span>):</span><br><span class="line">        model.train()</span><br><span class="line">        total_loss = <span class="number">0</span></span><br><span class="line">        <span class="keyword">for</span> images, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">            images, labels = images.to(device), labels.to(device)</span><br><span class="line">            optimizer.zero_grad()</span><br><span class="line">            loss = criterion(model(images), labels)</span><br><span class="line">            loss.backward()</span><br><span class="line">            optimizer.step()</span><br><span class="line">            total_loss += loss.item()</span><br><span class="line"></span><br><span class="line">        model.<span class="built_in">eval</span>()</span><br><span class="line">        correct = total = <span class="number">0</span></span><br><span class="line">        <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">            <span class="keyword">for</span> images, labels <span class="keyword">in</span> test_loader:</span><br><span class="line">                images, labels = images.to(device), labels.to(device)</span><br><span class="line">                _, predicted = torch.<span class="built_in">max</span>(model(images), <span class="number">1</span>)</span><br><span class="line">                total += labels.size(<span class="number">0</span>)</span><br><span class="line">                correct += (predicted == labels).<span class="built_in">sum</span>().item()</span><br><span class="line"></span><br><span class="line">        scheduler.step()</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch:2d&#125;</span>: loss=<span class="subst">&#123;total_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>, acc=<span class="subst">&#123;correct/total:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&#x27;__main__&#x27;</span>:</span><br><span class="line">    train()</span><br></pre></td></tr></table></figure><p>预期结果：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Epoch  1: loss=1.4167, acc=0.4765</span><br><span class="line">Epoch  5: loss=0.7895, acc=0.7188</span><br><span class="line">Epoch 10: loss=0.5825, acc=0.7924</span><br><span class="line">Epoch 15: loss=0.4321, acc=0.8257</span><br><span class="line">Epoch 20: loss=0.3380, acc=0.8432</span><br></pre></td></tr></table></figure><p><strong>84.3%</strong>。比瞎猜（10%）好很多，但远不如 MNIST 的 99%。</p><hr><h2 id="二、数据增强：免费的精度"><a href="#二、数据增强：免费的精度" class="headerlink" title="二、数据增强：免费的精度"></a>二、数据增强：免费的精度</h2><p>CIFAR-10 训练集只有 5 万张图。数据增强相当于白送你更多数据：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 带增强的数据加载</span></span><br><span class="line">train_transform = transforms.Compose([</span><br><span class="line">    transforms.RandomCrop(<span class="number">32</span>, padding=<span class="number">4</span>),     <span class="comment"># 随机裁剪，补零4像素</span></span><br><span class="line">    transforms.RandomHorizontalFlip(),         <span class="comment"># 随机水平翻转</span></span><br><span class="line">    transforms.ColorJitter(brightness=<span class="number">0.2</span>,     <span class="comment"># 随机调亮度</span></span><br><span class="line">                          contrast=<span class="number">0.2</span>),       <span class="comment"># 随机调对比度</span></span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(mean=[<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>],</span><br><span class="line">                         std=[<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>])</span><br><span class="line">])</span><br></pre></td></tr></table></figure><p>上面四行代码改了之后，跑 20 轮：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Epoch  1: loss=1.5232, acc=0.4421   # 一开始更难了（因为图像被随机改了）</span><br><span class="line">Epoch  5: loss=1.0012, acc=0.6484</span><br><span class="line">Epoch 10: loss=0.7843, acc=0.7412</span><br><span class="line">Epoch 15: loss=0.6201, acc=0.8125</span><br><span class="line">Epoch 20: loss=0.4972, acc=0.8701</span><br></pre></td></tr></table></figure><p><strong>87.0%</strong>，比基线高了 2.7%。</p><p>而且注意一个细节：没有增强时，训练 loss 远低于测试 loss（过拟合的苗头）。加了增强后两者差距缩小——<strong>泛化能力更强。</strong></p><blockquote><p><strong>重要提醒：</strong> 数据增强只能应用到训练集！测试集只用 Normalize。如果对测试集也做 RandomCrop，每次评估结果都会变，你就不知道模型到底怎样。</p></blockquote><hr><h2 id="三、迁移学习：站在巨人肩上"><a href="#三、迁移学习：站在巨人肩上" class="headerlink" title="三、迁移学习：站在巨人肩上"></a>三、迁移学习：站在巨人肩上</h2><p>接下来是<strong>最大的飞跃</strong>。用一个在 ImageNet（1400 万张图片）上预训练好的 ResNet-18，迁移学习到 CIFAR-10。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torchvision.models <span class="keyword">import</span> resnet18</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TransferModel</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="comment"># 加载预训练 ResNet-18</span></span><br><span class="line">        <span class="variable language_">self</span>.backbone = resnet18(pretrained=<span class="literal">True</span>)</span><br><span class="line">        <span class="comment"># 替换最后一层分类头</span></span><br><span class="line">        in_features = <span class="variable language_">self</span>.backbone.fc.in_features</span><br><span class="line">        <span class="variable language_">self</span>.backbone.fc = nn.Linear(in_features, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="comment"># CIFAR-10 是 32×32，ResNet 要求 224×224</span></span><br><span class="line">        <span class="comment"># 上采样到 ResNet 的输入尺寸</span></span><br><span class="line">        x = torch.nn.functional.interpolate(x, size=(<span class="number">224</span>, <span class="number">224</span>),</span><br><span class="line">                                            mode=<span class="string">&#x27;bilinear&#x27;</span>, align_corners=<span class="literal">False</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.backbone(x)</span><br></pre></td></tr></table></figure><p>但 ResNet-18 有 1100 万参数，全套微调太慢了。更好的做法：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 冻结 backbone，只训练最后的分类头</span></span><br><span class="line">model = TransferModel()</span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> model.backbone.parameters():</span><br><span class="line">    param.requires_grad = <span class="literal">False</span>  <span class="comment"># backbone 不更新</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 只优化新加的分类头</span></span><br><span class="line">optimizer = torch.optim.Adam(model.backbone.fc.parameters(), lr=<span class="number">0.001</span>)</span><br></pre></td></tr></table></figure><p>冻结后训练 10 轮：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Epoch  1: loss=0.8421, acc=0.7415</span><br><span class="line">Epoch  5: loss=0.5395, acc=0.8093</span><br><span class="line">Epoch 10: loss=0.4837, acc=0.8227</span><br></pre></td></tr></table></figure><p><strong>82.3%</strong>——只用 10 轮，只训分类头，不碰 1100 万参数。</p><p>如果再加 10 轮<strong>全量微调</strong>（解冻 backbone，lr 降到 1e-4）：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 第11轮开始：解冻 backbone，低学习率微调</span></span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> model.backbone.parameters():</span><br><span class="line">    param.requires_grad = <span class="literal">True</span></span><br><span class="line">optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">1e-4</span>)</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Epoch 11: loss=0.3512, acc=0.8813</span><br><span class="line">Epoch 15: loss=0.2216, acc=0.9112</span><br><span class="line">Epoch 20: loss=0.1892, acc=0.9219</span><br></pre></td></tr></table></figure><p><strong>92.2%</strong>——比普通 CNN + 数据增强高了 5 个点。</p><hr><h2 id="四、三方案对比"><a href="#四、三方案对比" class="headerlink" title="四、三方案对比"></a>四、三方案对比</h2><table><thead><tr><th>方案</th><th>参数量</th><th>20 轮精度</th><th>训练时间（GPU）</th></tr></thead><tbody><tr><td>普通 CNN</td><td>4.5M</td><td>84.3%</td><td>~8min</td></tr><tr><td>+ 数据增强</td><td>4.5M</td><td>87.0%</td><td>~9min（预处理多了）</td></tr><tr><td>+ ResNet 迁移学习</td><td>11.1M</td><td>92.2%</td><td>~15min</td></tr></tbody></table><p><strong>关键结论：</strong></p><ul><li><strong>数据增强是性价比最高的技巧</strong>——不要钱，改一行代码就 +2.7%</li><li><strong>迁移学习是上限最高的方案</strong>——+7.9%，但预训练模型很难在 CPU 上跑</li></ul><hr><h2 id="五、完整代码"><a href="#五、完整代码" class="headerlink" title="五、完整代码"></a>五、完整代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;cifar10_demo.py - CIFAR-10 图像分类完整代码&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> datasets, transforms</span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据加载（训练集带增强）</span></span><br><span class="line">train_transform = transforms.Compose([</span><br><span class="line">    transforms.RandomCrop(<span class="number">32</span>, padding=<span class="number">4</span>),</span><br><span class="line">    transforms.RandomHorizontalFlip(),</span><br><span class="line">    transforms.ColorJitter(brightness=<span class="number">0.2</span>, contrast=<span class="number">0.2</span>),</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize([<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>],</span><br><span class="line">                         [<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>])</span><br><span class="line">])</span><br><span class="line">test_transform = transforms.Compose([</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize([<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>],</span><br><span class="line">                         [<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>])</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(</span><br><span class="line">    datasets.CIFAR10(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>,  download=<span class="literal">True</span>, transform=train_transform),</span><br><span class="line">    batch_size=<span class="number">128</span>, shuffle=<span class="literal">True</span>, num_workers=<span class="number">2</span>)</span><br><span class="line">test_loader = DataLoader(</span><br><span class="line">    datasets.CIFAR10(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">False</span>, download=<span class="literal">True</span>, transform=test_transform),</span><br><span class="line">    batch_size=<span class="number">256</span>, shuffle=<span class="literal">False</span>, num_workers=<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 预训练 ResNet-18</span></span><br><span class="line"><span class="keyword">from</span> torchvision.models <span class="keyword">import</span> resnet18</span><br><span class="line"></span><br><span class="line">model = resnet18(pretrained=<span class="literal">True</span>)</span><br><span class="line">model.fc = nn.Linear(model.fc.in_features, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">model.to(device)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line"></span><br><span class="line"><span class="comment"># Phase 1: 只训分类头</span></span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> model.parameters():</span><br><span class="line">    param.requires_grad = <span class="literal">False</span></span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> model.fc.parameters():</span><br><span class="line">    param.requires_grad = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">optimizer = torch.optim.Adam(model.fc.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">11</span>):</span><br><span class="line">    model.train()</span><br><span class="line">    loss_total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> images, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">        images, labels = images.to(device), labels.to(device)</span><br><span class="line">        images = nn.functional.interpolate(images, (<span class="number">224</span>, <span class="number">224</span>),</span><br><span class="line">                                           mode=<span class="string">&#x27;bilinear&#x27;</span>, align_corners=<span class="literal">False</span>)</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        loss = criterion(model(images), labels)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        loss_total += loss.item()</span><br><span class="line"></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    correct = total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> images, labels <span class="keyword">in</span> test_loader:</span><br><span class="line">            images, labels = images.to(device), labels.to(device)</span><br><span class="line">            images = nn.functional.interpolate(images, (<span class="number">224</span>, <span class="number">224</span>),</span><br><span class="line">                                               mode=<span class="string">&#x27;bilinear&#x27;</span>, align_corners=<span class="literal">False</span>)</span><br><span class="line">            _, predicted = torch.<span class="built_in">max</span>(model(images), <span class="number">1</span>)</span><br><span class="line">            total += labels.size(<span class="number">0</span>)</span><br><span class="line">            correct += (predicted == labels).<span class="built_in">sum</span>().item()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Phase1 Epoch <span class="subst">&#123;epoch:2d&#125;</span>: loss=<span class="subst">&#123;loss_total/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>, acc=<span class="subst">&#123;correct/total:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Phase 2: 全量微调</span></span><br><span class="line"><span class="keyword">for</span> param <span class="keyword">in</span> model.parameters():</span><br><span class="line">    param.requires_grad = <span class="literal">True</span></span><br><span class="line">optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">1e-4</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">11</span>, <span class="number">21</span>):</span><br><span class="line">    <span class="comment"># 同上训练循环</span></span><br><span class="line">    model.train()</span><br><span class="line">    loss_total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> images, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">        images, labels = images.to(device), labels.to(device)</span><br><span class="line">        images = nn.functional.interpolate(images, (<span class="number">224</span>, <span class="number">224</span>),</span><br><span class="line">                                           mode=<span class="string">&#x27;bilinear&#x27;</span>, align_corners=<span class="literal">False</span>)</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        loss = criterion(model(images), labels)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        loss_total += loss.item()</span><br><span class="line"></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    correct = total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> images, labels <span class="keyword">in</span> test_loader:</span><br><span class="line">            images, labels = images.to(device), labels.to(device)</span><br><span class="line">            images = nn.functional.interpolate(images, (<span class="number">224</span>, <span class="number">224</span>),</span><br><span class="line">                                               mode=<span class="string">&#x27;bilinear&#x27;</span>, align_corners=<span class="literal">False</span>)</span><br><span class="line">            _, predicted = torch.<span class="built_in">max</span>(model(images), <span class="number">1</span>)</span><br><span class="line">            total += labels.size(<span class="number">0</span>)</span><br><span class="line">            correct += (predicted == labels).<span class="built_in">sum</span>().item()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Phase2 Epoch <span class="subst">&#123;epoch:2d&#125;</span>: loss=<span class="subst">&#123;loss_total/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>, acc=<span class="subst">&#123;correct/total:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>GPU 的话约 15 分钟跑完。如果是 CPU，全量微调可能 2-3 小时——你可以在 Phase 1 后停，拎着 82% 的精度先玩玩。</strong></p></blockquote><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul><li>CIFAR-10 比 MNIST 难得多（84% vs 99%），但这才是真实世界的入门难度</li><li><strong>数据增强</strong>是白送的精调度，必须上</li><li><strong>迁移学习</strong>是做大模型的捷径——没人真的从零训了</li><li>学会了两阶段微调：先冻后解，又快又好</li></ul><p>接下来你可以：</p><ul><li>自己收集 10 张猫&#x2F;狗照片，用这个模型测试</li><li>把 ResNet-18 换成 ResNet-50，看看精度还能涨多少</li><li>学习 TensorBoard 来可视化训练过程</li><li>尝试用 YOLO 做目标检测——下一篇就是这个</li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%EF%BC%88CIFAR-10%EF%BC%89/</id>
    <link href="https://aijvs.com/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%EF%BC%88CIFAR-10%EF%BC%89/"/>
    <published>2026-07-11T04:00:00.000Z</published>
    <summary>用 PyTorch 实现 CIFAR-10 彩色图片分类，对比普通 CNN、数据增强和迁移学习的实际效果差距。</summary>
    <title>实战：图像分类（CIFAR-10）</title>
    <updated>2026-07-11T04:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="实战项目" scheme="https://aijvs.com/categories/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="PyTorch" scheme="https://aijvs.com/tags/PyTorch/"/>
    <category term="MNIST" scheme="https://aijvs.com/tags/MNIST/"/>
    <category term="实战项目" scheme="https://aijvs.com/tags/%E5%AE%9E%E6%88%98%E9%A1%B9%E7%9B%AE/"/>
    <category term="手写数字识别" scheme="https://aijvs.com/tags/%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB/"/>
    <category term="卷积神经网络" scheme="https://aijvs.com/tags/%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
    <content>
      <![CDATA[<h2 id="引子"><a href="#引子" class="headerlink" title="引子"></a>引子</h2><p>你学了 PyTorch，懂了张量怎么算、梯度怎么传——但脑子里还是空的。</p><p><strong>“学完了理论，我不知道怎么组合起来。”</strong></p><p>这是我从后台看到最多的私信。所以这篇来了：一次完整的实战，从数据到模型到调优。</p><p>你能写出一个识别手写数字的程序，就说明你真正理解了深度学习的基础管线。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN 卷积神经网络</a></li></ul><p>看完这两篇再来，手感会好很多。</p><hr><h2 id="一、MNIST-数据集长什么样？"><a href="#一、MNIST-数据集长什么样？" class="headerlink" title="一、MNIST 数据集长什么样？"></a>一、MNIST 数据集长什么样？</h2><p>MNIST 是计算机视觉界的”Hello World”。</p><ul><li>训练集：60,000 张 28×28 灰度手写数字（0-9）</li><li>测试集：10,000 张</li><li>每个像素 0-255，白色背景、黑色笔迹</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 看一眼数据长什么样子</span></span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torchvision</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line">train_data = torchvision.datasets.MNIST(root=<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>, download=<span class="literal">True</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;形状: <span class="subst">&#123;train_data.data.shape&#125;</span>&quot;</span>)   <span class="comment"># torch.Size([60000, 28, 28])</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;标签: <span class="subst">&#123;train_data.targets[:<span class="number">10</span>]&#125;</span>&quot;</span>) <span class="comment"># tensor([5, 0, 4, 1, 9, 2, 1, 3, 1, 4])</span></span><br></pre></td></tr></table></figure><p>如果这行代码跑不了，说明你缺 <code>torchvision</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install torchvision matplotlib</span><br></pre></td></tr></table></figure><hr><h2 id="二、方案一：全连接网络（基线）"><a href="#二、方案一：全连接网络（基线）" class="headerlink" title="二、方案一：全连接网络（基线）"></a>二、方案一：全连接网络（基线）</h2><h3 id="2-1-数据加载"><a href="#2-1-数据加载" class="headerlink" title="2.1 数据加载"></a>2.1 数据加载</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> datasets, transforms</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="comment"># 预处理：转 Tensor 并归一化到 [0,1]</span></span><br><span class="line">transform = transforms.Compose([</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize((<span class="number">0.1307</span>,), (<span class="number">0.3081</span>,))  <span class="comment"># MNIST 的均值和标准差</span></span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">train_dataset = datasets.MNIST(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>,  download=<span class="literal">True</span>, transform=transform)</span><br><span class="line">test_dataset  = datasets.MNIST(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">False</span>, download=<span class="literal">True</span>, transform=transform)</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(train_dataset, batch_size=<span class="number">64</span>, shuffle=<span class="literal">True</span>)</span><br><span class="line">test_loader  = DataLoader(test_dataset,  batch_size=<span class="number">1000</span>, shuffle=<span class="literal">False</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>为什么用 Normalize？</strong> 原始像素值 0-255 方差很大，模型训练不稳定。归一化后均值为 0、方差为 1，梯度更新更平滑。</p></blockquote><h3 id="2-2-定义模型"><a href="#2-2-定义模型" class="headerlink" title="2.2 定义模型"></a>2.2 定义模型</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">FCModel</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;3 层全连接网络&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.fc1 = nn.Linear(<span class="number">28</span>*<span class="number">28</span>, <span class="number">128</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc2 = nn.Linear(<span class="number">128</span>, <span class="number">64</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc3 = nn.Linear(<span class="number">64</span>, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="comment"># x: [batch, 1, 28, 28] → [batch, 784]</span></span><br><span class="line">        x = x.view(x.size(<span class="number">0</span>), -<span class="number">1</span>)</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc1(x))</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc2(x))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc3(x)  <span class="comment"># 交叉熵损失自带 softmax，这里不用加</span></span><br></pre></td></tr></table></figure><h3 id="2-3-训练函数"><a href="#2-3-训练函数" class="headerlink" title="2.3 训练函数"></a>2.3 训练函数</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">train_one_epoch</span>(<span class="params">model, loader, optimizer, criterion, device</span>):</span><br><span class="line">    model.train()</span><br><span class="line">    total_loss = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> images, labels <span class="keyword">in</span> loader:</span><br><span class="line">        images, labels = images.to(device), labels.to(device)</span><br><span class="line"></span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        outputs = model(images)</span><br><span class="line">        loss = criterion(outputs, labels)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line"></span><br><span class="line">        total_loss += loss.item()</span><br><span class="line">    <span class="keyword">return</span> total_loss / <span class="built_in">len</span>(loader)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">evaluate</span>(<span class="params">model, loader, device</span>):</span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    correct = <span class="number">0</span></span><br><span class="line">    total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> images, labels <span class="keyword">in</span> loader:</span><br><span class="line">            images, labels = images.to(device), labels.to(device)</span><br><span class="line">            outputs = model(images)</span><br><span class="line">            _, predicted = torch.<span class="built_in">max</span>(outputs, <span class="number">1</span>)</span><br><span class="line">            total += labels.size(<span class="number">0</span>)</span><br><span class="line">            correct += (predicted == labels).<span class="built_in">sum</span>().item()</span><br><span class="line">    <span class="keyword">return</span> correct / total</span><br></pre></td></tr></table></figure><h3 id="2-4-训练"><a href="#2-4-训练" class="headerlink" title="2.4 训练"></a>2.4 训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">fc_model = FCModel().to(device)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line">optimizer = torch.optim.Adam(fc_model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line">epochs = <span class="number">5</span></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, epochs + <span class="number">1</span>):</span><br><span class="line">    loss = train_one_epoch(fc_model, train_loader, optimizer, criterion, device)</span><br><span class="line">    acc  = evaluate(fc_model, test_loader, device)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: loss=<span class="subst">&#123;loss:<span class="number">.4</span>f&#125;</span>, test_acc=<span class="subst">&#123;acc:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Epoch 1: loss=0.3372, test_acc=0.9372</span><br><span class="line">Epoch 2: loss=0.1623, test_acc=0.9584</span><br><span class="line">Epoch 3: loss=0.1134, test_acc=0.9650</span><br><span class="line">Epoch 4: loss=0.0855, test_acc=0.9694</span><br><span class="line">Epoch 5: loss=0.0673, test_acc=0.9739</span><br></pre></td></tr></table></figure><p>5 轮训练，测试准确率 <strong>97.4%</strong>。已经不错了——但 CNN 能做得更好。</p><hr><h2 id="三、方案二：CNN（改进版）"><a href="#三、方案二：CNN（改进版）" class="headerlink" title="三、方案二：CNN（改进版）"></a>三、方案二：CNN（改进版）</h2><p>全连接网络的缺点是<strong>丢掉了空间结构</strong>——28×28 的图片展平成 784 个独立像素。CNN 保留了 2D 结构。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CNNModel</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;2 层卷积 + 2 层全连接&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = nn.Conv2d(<span class="number">1</span>, <span class="number">32</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>)  <span class="comment"># 28×28 → 28×28</span></span><br><span class="line">        <span class="variable language_">self</span>.conv2 = nn.Conv2d(<span class="number">32</span>, <span class="number">64</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>) <span class="comment"># 14×14 → 14×14</span></span><br><span class="line">        <span class="variable language_">self</span>.pool = nn.MaxPool2d(<span class="number">2</span>, <span class="number">2</span>)     <span class="comment"># 2×2 池化，宽高减半</span></span><br><span class="line">        <span class="variable language_">self</span>.fc1 = nn.Linear(<span class="number">64</span> * <span class="number">7</span> * <span class="number">7</span>, <span class="number">128</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc2 = nn.Linear(<span class="number">128</span>, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.conv1(x)))  <span class="comment"># [b,1,28,28] → [b,32,14,14]</span></span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.conv2(x)))  <span class="comment"># [b,32,14,14] → [b,64,7,7]</span></span><br><span class="line">        x = x.view(x.size(<span class="number">0</span>), -<span class="number">1</span>)                 <span class="comment"># [b, 64*7*7]</span></span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc1(x))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc2(x)</span><br></pre></td></tr></table></figure><p>一样的训练代码，唯一的区别是换模型：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">cnn_model = CNNModel().to(device)</span><br><span class="line">optimizer = torch.optim.Adam(cnn_model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, epochs + <span class="number">1</span>):</span><br><span class="line">    loss = train_one_epoch(cnn_model, train_loader, optimizer, criterion, device)</span><br><span class="line">    acc  = evaluate(cnn_model, test_loader, device)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: loss=<span class="subst">&#123;loss:<span class="number">.4</span>f&#125;</span>, test_acc=<span class="subst">&#123;acc:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>预期输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Epoch 1: loss=0.2022, test_acc=0.9684</span><br><span class="line">Epoch 2: loss=0.0631, test_acc=0.9832</span><br><span class="line">Epoch 3: loss=0.0422, test_acc=0.9867</span><br><span class="line">Epoch 4: loss=0.0296, test_acc=0.9902</span><br><span class="line">Epoch 5: loss=0.0227, test_acc=0.9914</span><br></pre></td></tr></table></figure><p><strong>CNN 在 Epoch 1 就追上了全连接网络 5 轮的准确率，5 轮后 99.1%。</strong></p><p>差出来的 1.7% 就是”保住空间结构”带来的差距。</p><hr><h2 id="四、对比与解读"><a href="#四、对比与解读" class="headerlink" title="四、对比与解读"></a>四、对比与解读</h2><table><thead><tr><th>指标</th><th>全连接网络</th><th>CNN</th></tr></thead><tbody><tr><td>参数量</td><td>109,386</td><td>387,786</td></tr><tr><td>5 轮准确率</td><td>97.4%</td><td>99.1%</td></tr><tr><td>每轮训练时间（CPU）</td><td>~15s</td><td>~30s</td></tr><tr><td>每轮训练时间（GPU）</td><td>~3s</td><td>~5s</td></tr></tbody></table><p>CNN 参数量虽然大，但在 GPU 上差距不大。<strong>对于图像类任务，CNN 是绝对首选。</strong></p><h3 id="为什么不是-100-？"><a href="#为什么不是-100-？" class="headerlink" title="为什么不是 100%？"></a>为什么不是 100%？</h3><p>99.1% 离 100% 差的那 0.9%，看这里——这些连人都认不出来：</p><p>![MNIST 难例](无法识别的样本，比如连笔、缺损、歪斜的 4&#x2F;9 混淆)</p><p><strong>99.1% 说明不是模型问题，是数据本身的噪声。</strong> 真实场景里，99% 精度已经足够部署。</p><hr><h2 id="五、完整代码（一键运行）"><a href="#五、完整代码（一键运行）" class="headerlink" title="五、完整代码（一键运行）"></a>五、完整代码（一键运行）</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;&quot;&quot;mnist_demo.py - 手写数字识别完整代码&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">from</span> torch <span class="keyword">import</span> nn</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> datasets, transforms</span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 数据</span></span><br><span class="line">transform = transforms.Compose([</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize((<span class="number">0.1307</span>,), (<span class="number">0.3081</span>,))</span><br><span class="line">])</span><br><span class="line">train_loader = DataLoader(</span><br><span class="line">    datasets.MNIST(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>, download=<span class="literal">True</span>, transform=transform),</span><br><span class="line">    batch_size=<span class="number">64</span>, shuffle=<span class="literal">True</span>)</span><br><span class="line">test_loader = DataLoader(</span><br><span class="line">    datasets.MNIST(<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">False</span>, download=<span class="literal">True</span>, transform=transform),</span><br><span class="line">    batch_size=<span class="number">1000</span>, shuffle=<span class="literal">False</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 模型（CNN）</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CNNModel</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = nn.Conv2d(<span class="number">1</span>, <span class="number">32</span>, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.conv2 = nn.Conv2d(<span class="number">32</span>, <span class="number">64</span>, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.pool = nn.MaxPool2d(<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc1 = nn.Linear(<span class="number">64</span>*<span class="number">7</span>*<span class="number">7</span>, <span class="number">128</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc2 = nn.Linear(<span class="number">128</span>, <span class="number">10</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.conv1(x)))</span><br><span class="line">        x = <span class="variable language_">self</span>.pool(torch.relu(<span class="variable language_">self</span>.conv2(x)))</span><br><span class="line">        x = x.view(x.size(<span class="number">0</span>), -<span class="number">1</span>)</span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.fc1(x))</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.fc2(x)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 训练</span></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line">model = CNNModel().to(device)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line">optimizer = torch.optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">6</span>):</span><br><span class="line">    model.train()</span><br><span class="line">    total_loss = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> images, labels <span class="keyword">in</span> train_loader:</span><br><span class="line">        images, labels = images.to(device), labels.to(device)</span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        loss = criterion(model(images), labels)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line">        total_loss += loss.item()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 测试</span></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    correct = total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> images, labels <span class="keyword">in</span> test_loader:</span><br><span class="line">            images, labels = images.to(device), labels.to(device)</span><br><span class="line">            outputs = model(images)</span><br><span class="line">            _, predicted = torch.<span class="built_in">max</span>(outputs, <span class="number">1</span>)</span><br><span class="line">            total += labels.size(<span class="number">0</span>)</span><br><span class="line">            correct += (predicted == labels).<span class="built_in">sum</span>().item()</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Epoch <span class="subst">&#123;epoch&#125;</span>: loss=<span class="subst">&#123;total_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span>, acc=<span class="subst">&#123;correct/total:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><p>保存为 <code>mnist_demo.py</code>，直接 <code>python mnist_demo.py</code> 就能跑。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>你从这篇学到了三件事：</p><ul><li><strong>全连接网络能做 MNIST，但 CNN 更好</strong>（97.4% → 99.1%）</li><li><strong>深度学习的关键管线</strong>：DataLoader → Model → Loss → Optimizer → Loop</li><li><strong>归一化和卷积核</strong>这些看起来很小的细节，对结果影响巨大</li></ul><p>下一步可以尝试：</p><ul><li>增加 Dropout 和数据增强，看看能不能冲 99.5%</li><li>换 ResNet-18，看看超大网络有没有过拟合</li><li>用这篇的代码，试着识别你自己的手写数字</li></ul><p>下一篇我们来挑战 CIFAR-10——真正的彩色图片分类。</p>]]>
    </content>
    <id>https://aijvs.com/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB%EF%BC%88MNIST%EF%BC%89/</id>
    <link href="https://aijvs.com/2026/07/11/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E8%AF%86%E5%88%AB%EF%BC%88MNIST%EF%BC%89/"/>
    <published>2026-07-11T02:00:00.000Z</published>
    <summary>从零实现 MNIST 手写数字识别，对比全连接网络和 CNN 的性能差异，完整代码可运行。</summary>
    <title>实战：手写数字识别（MNIST）</title>
    <updated>2026-07-11T02:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="自然语言处理" scheme="https://aijvs.com/categories/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="NLP" scheme="https://aijvs.com/tags/NLP/"/>
    <category term="自然语言处理" scheme="https://aijvs.com/tags/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/"/>
    <category term="词向量" scheme="https://aijvs.com/tags/%E8%AF%8D%E5%90%91%E9%87%8F/"/>
    <category term="Word2Vec" scheme="https://aijvs.com/tags/Word2Vec/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><blockquote><p>对计算机来说，”你好”和”hello”只是两个字节序列，它不懂”你好”背后的含义。</p></blockquote><p><strong>NLP（自然语言处理）</strong> 要做的事就是让计算机理解人类语言。但文本数据有个麻烦——它不像图片那样天然有像素坐标结构。</p><p>本文带你走完 NLP 的标准流程：<strong>原始文本 → 清洗 → 分词 → 向量化 → 词嵌入</strong>，这是后续一切 NLP 任务的基础。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%EF%BC%9A%E6%A6%82%E5%BF%B5%E4%B8%8E%E5%88%86%E7%B1%BB%E5%85%A8%E8%A7%A3/">机器学习入门：概念与分类全解</a></li><li><a href="/2026/06/17/Python%E7%BC%96%E7%A8%8B%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E4%BB%8E%E9%9B%B6%E6%90%AD%E5%BB%BA%E4%BD%A0%E7%9A%84AI%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/">Python 编程基础（一）：从零搭建你的AI开发环境</a></li></ul><hr><h2 id="一、NLP-的核心挑战"><a href="#一、NLP-的核心挑战" class="headerlink" title="一、NLP 的核心挑战"></a>一、NLP 的核心挑战</h2><h3 id="1-1-语言-vs-计算机"><a href="#1-1-语言-vs-计算机" class="headerlink" title="1.1 语言 vs 计算机"></a>1.1 语言 vs 计算机</h3><table><thead><tr><th align="center">语言</th><th align="center">计算机</th></tr></thead><tbody><tr><td align="center">“苹果很好吃”</td><td align="center">字节序列</td></tr><tr><td align="center">“我今天买了苹果手机”</td><td align="center">同一个词，不同意思</td></tr><tr><td align="center">“I am running” ~ “The running water”</td><td align="center">同一个词，不同词性</td></tr><tr><td align="center">“苹果很好吃” ~ “我吃了苹果”</td><td align="center">“苹果”出现了位置变了</td></tr></tbody></table><p><strong>三个核心问题：</strong></p><ol><li><strong>分词</strong> — 一句话拆成什么单位？</li><li><strong>歧义</strong> — 同一个词在不同上下文什么意思？</li><li><strong>表示</strong> — 怎么把词变成计算机能算的数字向量？</li></ol><h3 id="1-2-NLP-的典型任务"><a href="#1-2-NLP-的典型任务" class="headerlink" title="1.2 NLP 的典型任务"></a>1.2 NLP 的典型任务</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">分词/词性标注 ─── 基础任务（管道上游）</span><br><span class="line">     ↓</span><br><span class="line">命名实体识别 (NER) ─── &quot;2026年7月3日&quot;是日期，&quot;北京&quot;是地点</span><br><span class="line">     ↓</span><br><span class="line">文本分类/情感分析 ─── 正面/负面/中性</span><br><span class="line">     ↓</span><br><span class="line">机器翻译/摘要/问答 ─── 复杂任务</span><br></pre></td></tr></table></figure><hr><h2 id="二、文本预处理"><a href="#二、文本预处理" class="headerlink" title="二、文本预处理"></a>二、文本预处理</h2><h3 id="2-1-分词（Tokenization）"><a href="#2-1-分词（Tokenization）" class="headerlink" title="2.1 分词（Tokenization）"></a>2.1 分词（Tokenization）</h3><p>分词是把文本拆成最小语义单位。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># English — 简单，直接用空格+标点</span></span><br><span class="line">text = <span class="string">&quot;I don&#x27;t like this movie at all.&quot;</span></span><br><span class="line">tokens = [<span class="string">&quot;I&quot;</span>, <span class="string">&quot;don&#x27;t&quot;</span>, <span class="string">&quot;like&quot;</span>, <span class="string">&quot;this&quot;</span>, <span class="string">&quot;movie&quot;</span>, <span class="string">&quot;at&quot;</span>, <span class="string">&quot;all&quot;</span>, <span class="string">&quot;.&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># BPE (Byte Pair Encoding) — GPT/BERT 用的分词法</span></span><br><span class="line"><span class="comment"># &quot;unbelievable&quot; → [&quot;un&quot;, &quot;believ&quot;, &quot;able&quot;]</span></span><br><span class="line"><span class="comment"># 优点是能处理任何没见过的词</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装</span></span><br><span class="line"><span class="comment"># pip install nltk spacy jieba</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># NLTK</span></span><br><span class="line"><span class="keyword">from</span> nltk.tokenize <span class="keyword">import</span> word_tokenize</span><br><span class="line">tokens = word_tokenize(<span class="string">&quot;I don&#x27;t like this movie at all.&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(tokens)</span><br><span class="line"><span class="comment"># [&#x27;I&#x27;, &#x27;do&#x27;, &quot;n&#x27;t&quot;, &#x27;like&#x27;, &#x27;this&#x27;, &#x27;movie&#x27;, &#x27;at&#x27;, &#x27;all&#x27;, &#x27;.&#x27;]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 中文分词 — jieba</span></span><br><span class="line"><span class="keyword">import</span> jieba</span><br><span class="line">text = <span class="string">&quot;我在北京清华大学读书，未来想要研究人工智能。&quot;</span></span><br><span class="line">tokens = <span class="built_in">list</span>(jieba.cut(text))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;/&#x27;</span>.join(tokens))</span><br><span class="line"><span class="comment"># 我/在/北京/清华大学/读书/，/未来/想要/研究/人工/智能/。</span></span><br></pre></td></tr></table></figure><h3 id="2-2-文本清洗"><a href="#2-2-文本清洗" class="headerlink" title="2.2 文本清洗"></a>2.2 文本清洗</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">clean_text</span>(<span class="params">text</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;基础的文本清洗&quot;&quot;&quot;</span></span><br><span class="line">    <span class="comment"># 转小写</span></span><br><span class="line">    text = text.lower()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 去 HTML 标签</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;&lt;[^&gt;]+&gt;&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 去 URL</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;http\S+|www\S+&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 去 @用户和 #话题</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;@\w+|#\w+&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 去特殊字符但保留标点</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;[^\w\s\.\,\!\?]&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 合并多余空格</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;\s+&#x27;</span>, <span class="string">&#x27; &#x27;</span>, text).strip()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> text</span><br></pre></td></tr></table></figure><h3 id="2-3-词干提取与词形还原"><a href="#2-3-词干提取与词形还原" class="headerlink" title="2.3 词干提取与词形还原"></a>2.3 词干提取与词形还原</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> nltk.stem <span class="keyword">import</span> PorterStemmer, WordNetLemmatizer</span><br><span class="line"></span><br><span class="line">stemmer = PorterStemmer()</span><br><span class="line">lemmatizer = WordNetLemmatizer()</span><br><span class="line"></span><br><span class="line">words = [<span class="string">&quot;running&quot;</span>, <span class="string">&quot;runner&quot;</span>, <span class="string">&quot;ran&quot;</span>, <span class="string">&quot;better&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> w <span class="keyword">in</span> words:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;w:10s&#125;</span> → 词干: <span class="subst">&#123;stemmer.stem(w):10s&#125;</span> | 词形还原: <span class="subst">&#123;lemmatizer.lemmatize(w, pos=<span class="string">&#x27;v&#x27;</span>):10s&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出:</span></span><br><span class="line"><span class="comment"># running    → 词干: run       | 词形还原: run</span></span><br><span class="line"><span class="comment"># runner     → 词干: runner    | 词形还原: runner</span></span><br><span class="line"><span class="comment"># ran        → 词干: ran       | 词形还原: run</span></span><br><span class="line"><span class="comment"># better     → 词干: better    | 词形还原: better (词性修正后: good)</span></span><br></pre></td></tr></table></figure><p><strong>区别：</strong> 词干提取靠规则砍（”running” → “run”），词形还原则查词典（”ran” → “run”）。词形还原本质上更准确，但需要词性标注辅助。</p><h3 id="2-4-停用词移除"><a href="#2-4-停用词移除" class="headerlink" title="2.4 停用词移除"></a>2.4 停用词移除</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> nltk.corpus <span class="keyword">import</span> stopwords</span><br><span class="line"></span><br><span class="line">stop_words = <span class="built_in">set</span>(stopwords.words(<span class="string">&#x27;english&#x27;</span>))</span><br><span class="line"></span><br><span class="line">tokens = [<span class="string">&quot;this&quot;</span>, <span class="string">&quot;movie&quot;</span>, <span class="string">&quot;is&quot;</span>, <span class="string">&quot;really&quot;</span>, <span class="string">&quot;good&quot;</span>]</span><br><span class="line">filtered = [t <span class="keyword">for</span> t <span class="keyword">in</span> tokens <span class="keyword">if</span> t <span class="keyword">not</span> <span class="keyword">in</span> stop_words]</span><br><span class="line"><span class="built_in">print</span>(filtered)</span><br><span class="line"><span class="comment"># [&#x27;movie&#x27;, &#x27;really&#x27;, &#x27;good&#x27;]</span></span><br></pre></td></tr></table></figure><blockquote><p>❗ 并非所有任务都适合去停用词。情感分析中 “not”、”but” 这类词很重要。</p></blockquote><hr><h2 id="三、文本向量化"><a href="#三、文本向量化" class="headerlink" title="三、文本向量化"></a>三、文本向量化</h2><h3 id="3-1-One-Hot-编码"><a href="#3-1-One-Hot-编码" class="headerlink" title="3.1 One-Hot 编码"></a>3.1 One-Hot 编码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 词表: [&quot;爱&quot;, &quot;很&quot;, &quot;开心&quot;, &quot;恨&quot;, &quot;难过&quot;, &quot;无聊&quot;]</span></span><br><span class="line"><span class="comment"># 每个词是一个 6 维向量，只有一位是 1</span></span><br><span class="line"></span><br><span class="line"><span class="string">&quot;爱&quot;</span>    → [<span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>]</span><br><span class="line"><span class="string">&quot;开心&quot;</span>  → [<span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>]</span><br><span class="line"><span class="string">&quot;无聊&quot;</span>  → [<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>]</span><br></pre></td></tr></table></figure><p><strong>缺点：</strong> 词表越大向量越长，且任意两个词的相似度都是 0。</p><h3 id="3-2-TF-IDF"><a href="#3-2-TF-IDF" class="headerlink" title="3.2 TF-IDF"></a>3.2 TF-IDF</h3><p>TF-IDF 评估一个词对一篇文档的重要程度：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">TF(t, d) = 词 t 在文档 d 中出现的次数 / 文档 d 的总词数</span><br><span class="line">IDF(t) = log(总文档数 / 包含词 t 的文档数)</span><br><span class="line">TF-IDF = TF × IDF</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.feature_extraction.text <span class="keyword">import</span> TfidfVectorizer</span><br><span class="line"></span><br><span class="line">docs = [</span><br><span class="line">    <span class="string">&quot;I love deep learning and AI&quot;</span>,</span><br><span class="line">    <span class="string">&quot;I love pizza and pasta&quot;</span>,</span><br><span class="line">    <span class="string">&quot;Deep learning is fascinating&quot;</span>,</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">vectorizer = TfidfVectorizer()</span><br><span class="line">tfidf_matrix = vectorizer.fit_transform(docs)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看每个词的 TF-IDF 权重</span></span><br><span class="line">feature_names = vectorizer.get_feature_names_out()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;词表: <span class="subst">&#123;<span class="built_in">list</span>(feature_names)&#125;</span>&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;TF-IDF 矩阵形状: <span class="subst">&#123;tfidf_matrix.shape&#125;</span>&quot;</span>)  <span class="comment"># (3, 9)</span></span><br></pre></td></tr></table></figure><p>TF-IDF 的优势是<strong>能自动降低 “the”、”and” 等常见词的权重</strong>，突出有区分度的词。</p><h3 id="3-3-词向量（Word-Embedding）"><a href="#3-3-词向量（Word-Embedding）" class="headerlink" title="3.3 词向量（Word Embedding）"></a>3.3 词向量（Word Embedding）</h3><p>One-Hot 和 TF-IDF 的共同问题：<strong>不包含语义信息。</strong></p><p>词向量把每个词映射到低维连续向量（通常 50-300 维），语义相似的词向量距离更近：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&quot;国王&quot; - &quot;男人&quot; + &quot;女人&quot; ≈ &quot;女王&quot;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Gensim Word2Vec</span></span><br><span class="line"><span class="keyword">from</span> gensim.models <span class="keyword">import</span> Word2Vec</span><br><span class="line"></span><br><span class="line">sentences = [</span><br><span class="line">    [<span class="string">&quot;i&quot;</span>, <span class="string">&quot;love&quot;</span>, <span class="string">&quot;deep&quot;</span>, <span class="string">&quot;learning&quot;</span>],</span><br><span class="line">    [<span class="string">&quot;deep&quot;</span>, <span class="string">&quot;learning&quot;</span>, <span class="string">&quot;is&quot;</span>, <span class="string">&quot;awesome&quot;</span>],</span><br><span class="line">    [<span class="string">&quot;i&quot;</span>, <span class="string">&quot;love&quot;</span>, <span class="string">&quot;nlp&quot;</span>, <span class="string">&quot;and&quot;</span>, <span class="string">&quot;computer&quot;</span>, <span class="string">&quot;vision&quot;</span>],</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">model = Word2Vec(sentences, vector_size=<span class="number">100</span>, window=<span class="number">5</span>, min_count=<span class="number">1</span>, sg=<span class="number">0</span>)</span><br><span class="line"><span class="comment"># vector_size: 词向量维度</span></span><br><span class="line"><span class="comment"># window:     上下文窗口大小</span></span><br><span class="line"><span class="comment"># min_count:  最小出现次数</span></span><br><span class="line"><span class="comment"># sg:         CBOW(0) / Skip-gram(1)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 找相似词</span></span><br><span class="line">similar = model.wv.most_similar(<span class="string">&#x27;deep&#x27;</span>, topn=<span class="number">3</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;与 &#x27;deep&#x27; 最相似的词: <span class="subst">&#123;similar&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="3-4-预训练词向量"><a href="#3-4-预训练词向量" class="headerlink" title="3.4 预训练词向量"></a>3.4 预训练词向量</h3><p>自己训练词向量的时代已经过去了。现在直接用别人在大数据上训好的：</p><table><thead><tr><th align="center">模型</th><th align="center">维度</th><th align="center">训练数据</th><th align="center">特点</th></tr></thead><tbody><tr><td align="center">GloVe</td><td align="center">50&#x2F;100&#x2F;300</td><td align="center">60 亿词</td><td align="center">经典，基于全局共现</td></tr><tr><td align="center">FastText</td><td align="center">300</td><td align="center">160 亿词</td><td align="center">支持子词，能处理 OOV</td></tr><tr><td align="center"><strong>BERT</strong></td><td align="center">768</td><td align="center">33 亿词</td><td align="center"><strong>上下文相关</strong>——里程碑式突破</td></tr><tr><td align="center"><strong>GPT 系列</strong></td><td align="center">768-12288</td><td align="center">海量</td><td align="center">超大语言模型</td></tr></tbody></table><p><strong>重点：BERT 之前，词向量是静态的</strong>（”苹果”在”苹果很好吃”和”苹果手机”中向量一样）。BERT 之后，词向量变成<strong>上下文相关</strong>——同一个词在不同句子中向量不同。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span> AutoTokenizer, AutoModel</span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 用 BERT 生成上下文相关的词向量</span></span><br><span class="line">tokenizer = AutoTokenizer.from_pretrained(<span class="string">&#x27;bert-base-uncased&#x27;</span>)</span><br><span class="line">model = AutoModel.from_pretrained(<span class="string">&#x27;bert-base-uncased&#x27;</span>)</span><br><span class="line"></span><br><span class="line">texts = [</span><br><span class="line">    <span class="string">&quot;I bought an apple.&quot;</span>,</span><br><span class="line">    <span class="string">&quot;I bought an apple phone.&quot;</span>,</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> text <span class="keyword">in</span> texts:</span><br><span class="line">    inputs = tokenizer(text, return_tensors=<span class="string">&#x27;pt&#x27;</span>)</span><br><span class="line">    outputs = model(**inputs)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 取 token 的向量（最后一层隐藏状态）</span></span><br><span class="line">    embeddings = outputs.last_hidden_state  <span class="comment"># [1, seq_len, 768]</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># &quot;apple&quot; 在这两个句子中的向量不同！</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;&#x27;<span class="subst">&#123;text&#125;</span>&#x27; → 输出形状: <span class="subst">&#123;embeddings.shape&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><hr><h2 id="四、预处理流水线实战"><a href="#四、预处理流水线实战" class="headerlink" title="四、预处理流水线实战"></a>四、预处理流水线实战</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> nltk</span><br><span class="line"><span class="keyword">from</span> nltk.corpus <span class="keyword">import</span> stopwords</span><br><span class="line"><span class="keyword">from</span> nltk.stem <span class="keyword">import</span> WordNetLemmatizer</span><br><span class="line"></span><br><span class="line">nltk.download(<span class="string">&#x27;punkt&#x27;</span>)</span><br><span class="line">nltk.download(<span class="string">&#x27;stopwords&#x27;</span>)</span><br><span class="line">nltk.download(<span class="string">&#x27;wordnet&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">nlp_pipeline</span>(<span class="params">text</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;完整的 NLP 预处理流水线&quot;&quot;&quot;</span></span><br><span class="line">    <span class="comment"># 1. 清洗</span></span><br><span class="line">    text = re.sub(<span class="string">r&#x27;&lt;[^&gt;]+&gt;&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line">    text = re.sub(<span class="string">r&#x27;http\S+&#x27;</span>, <span class="string">&#x27;&#x27;</span>, text)</span><br><span class="line">    text = text.lower().strip()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 分词</span></span><br><span class="line">    tokens = nltk.word_tokenize(text)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3. 去停用词和标点</span></span><br><span class="line">    stop_words = <span class="built_in">set</span>(stopwords.words(<span class="string">&#x27;english&#x27;</span>))</span><br><span class="line">    tokens = [t <span class="keyword">for</span> t <span class="keyword">in</span> tokens</span><br><span class="line">              <span class="keyword">if</span> t <span class="keyword">not</span> <span class="keyword">in</span> stop_words <span class="keyword">and</span> t.isalpha()]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 4. 词形还原</span></span><br><span class="line">    lemmatizer = WordNetLemmatizer()</span><br><span class="line">    tokens = [lemmatizer.lemmatize(t) <span class="keyword">for</span> t <span class="keyword">in</span> tokens]</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> tokens</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试</span></span><br><span class="line">text = <span class="string">&quot;The amazing movies were not really appreciated by the critics!!!&quot;</span></span><br><span class="line"><span class="built_in">print</span>(nlp_pipeline(text))</span><br><span class="line"><span class="comment"># [&#x27;amazing&#x27;, &#x27;movie&#x27;, &#x27;really&#x27;, &#x27;appreciated&#x27;, &#x27;critic&#x27;]</span></span><br></pre></td></tr></table></figure><hr><h2 id="五、NLP-技术演进"><a href="#五、NLP-技术演进" class="headerlink" title="五、NLP 技术演进"></a>五、NLP 技术演进</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">2013  Word2Vec        ─── 词向量时代开始</span><br><span class="line">2014  Seq2Seq + Attention ─── 机器翻译突破</span><br><span class="line">2017  Transformer     ─── Attention Is All You Need</span><br><span class="line">2018  BERT            ─── 双向上下文</span><br><span class="line">          │</span><br><span class="line">          ├── GPT (2018) ─── 单向自回归</span><br><span class="line">          ├── RoBERTa (2019) ─── BERT 优化版</span><br><span class="line">          └── ELECTRA (2020) ─── 更高效的预训练</span><br><span class="line">          │</span><br><span class="line">2019  GPT-2           ─── 后起之秀</span><br><span class="line">2020  GPT-3           ─── 大模型爆发</span><br><span class="line">2021-2026  GPT-3.5/4, Claude, Gemini, LLaMA, DeepSeek</span><br></pre></td></tr></table></figure><p>现在 NLP 的主流范式是：<strong>预训练 → 微调</strong>。没有人再从零训词向量了。</p><hr><h2 id="六、总结"><a href="#六、总结" class="headerlink" title="六、总结"></a>六、总结</h2><table><thead><tr><th>知识点</th><th align="center">掌握</th></tr></thead><tbody><tr><td>NLP 的核心挑战</td><td align="center">✅</td></tr><tr><td>分词（中英文）</td><td align="center">✅</td></tr><tr><td>文本清洗与归一化</td><td align="center">✅</td></tr><tr><td>词干提取 vs 词形还原</td><td align="center">✅</td></tr><tr><td>TF-IDF 原理</td><td align="center">✅</td></tr><tr><td>Word2Vec 词向量</td><td align="center">✅</td></tr><tr><td>预训练词向量（BERT）</td><td align="center">✅ <strong>核心</strong></td></tr><tr><td>完整预处理流水线</td><td align="center">✅ <strong>实战</strong></td></tr></tbody></table><p><strong>下一步推荐：</strong></p><ul><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ARNN%E4%B8%8ELSTM/">神经网络架构详解：RNN 与 LSTM</a></li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li><li><a href="/2026/07/03/%E5%AE%9E%E6%88%98%EF%BC%9A%E6%83%85%E6%84%9F%E5%88%86%E6%9E%90IMDB/">实战：情感分析（IMDB）</a>（即将发布）</li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/03/NLP%E5%85%A5%E9%97%A8%EF%BC%9A%E6%96%87%E6%9C%AC%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E8%AF%8D%E5%90%91%E9%87%8F/</id>
    <link href="https://aijvs.com/2026/07/03/NLP%E5%85%A5%E9%97%A8%EF%BC%9A%E6%96%87%E6%9C%AC%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E8%AF%8D%E5%90%91%E9%87%8F/"/>
    <published>2026-07-03T09:00:00.000Z</published>
    <summary>NLP 自然语言处理入门教程：分词、词干提取、TF-IDF、Word2Vec 与预训练词向量的完整讲解。</summary>
    <title>NLP 入门：文本预处理与词向量</title>
    <updated>2026-07-03T09:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="计算机视觉" scheme="https://aijvs.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"/>
    <category term="入门教程" scheme="https://aijvs.com/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <category term="计算机视觉" scheme="https://aijvs.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"/>
    <category term="图像处理" scheme="https://aijvs.com/tags/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/"/>
    <category term="OpenCV" scheme="https://aijvs.com/tags/OpenCV/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>计算机视觉（CV）是 AI 最成熟的落地领域之一：</p><ul><li>手机人脸解锁</li><li>自动驾驶识别行人和车辆</li><li>医学影像辅助诊断</li><li>电商以图搜图</li><li>短视频滤镜和特效</li></ul><p>所有这些技术的底层都是<strong>图像处理</strong>。这篇文章从像素开始，带你走完”传统图像处理 → 深度学习特征提取 → CV 任务全景”的完整路径。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/06/17/AI%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0%E2%80%94%E2%80%94%E8%AE%A9%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%BC%9A%E7%9C%8B%E5%90%91%E9%87%8F/">数学基础（一）：线性代数——让机器学会看向量</a></li><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN 卷积神经网络</a></li></ul><p>看完 CNN 那篇再来，效果好一倍。</p><hr><h2 id="一、图像在计算机中的表示"><a href="#一、图像在计算机中的表示" class="headerlink" title="一、图像在计算机中的表示"></a>一、图像在计算机中的表示</h2><h3 id="1-1-一张图片-一个三维数组"><a href="#1-1-一张图片-一个三维数组" class="headerlink" title="1.1 一张图片 &#x3D; 一个三维数组"></a>1.1 一张图片 &#x3D; 一个三维数组</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">灰度图 (Grayscale):    [H×W]         — 每个像素 0-255 的亮度值</span><br><span class="line">彩色图 (RGB):          [H×W×3]       — 三个通道：红/绿/蓝</span><br><span class="line">RGBA 图:              [H×W×4]       — 多一个 Alpha（透明度）</span><br></pre></td></tr></table></figure><p>像素值范围通常是 0-255（8 位），深度学习会归一化到 0-1 或 -1~1。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cv2</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取图片</span></span><br><span class="line">img = cv2.imread(<span class="string">&#x27;example.jpg&#x27;</span>)</span><br><span class="line">img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  <span class="comment"># OpenCV 默认 BGR，转成 RGB</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;图片形状: <span class="subst">&#123;img_rgb.shape&#125;</span>&quot;</span>)  <span class="comment"># (height, width, channels)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;数据类型: <span class="subst">&#123;img_rgb.dtype&#125;</span>&quot;</span>)   <span class="comment"># uint8</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;像素范围: [<span class="subst">&#123;img_rgb.<span class="built_in">min</span>()&#125;</span>, <span class="subst">&#123;img_rgb.<span class="built_in">max</span>()&#125;</span>]&quot;</span>)</span><br><span class="line"></span><br><span class="line">plt.imshow(img_rgb)</span><br><span class="line">plt.axis(<span class="string">&#x27;off&#x27;</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure><h3 id="1-2-颜色空间"><a href="#1-2-颜色空间" class="headerlink" title="1.2 颜色空间"></a>1.2 颜色空间</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 转灰度</span></span><br><span class="line">gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)</span><br><span class="line"></span><br><span class="line"><span class="comment"># HSV（色调/饱和度/亮度 — 更符合人眼感知）</span></span><br><span class="line">hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)</span><br><span class="line"></span><br><span class="line"><span class="comment"># LAB（亮度 + 两个颜色通道 — 色彩差异更均匀）</span></span><br><span class="line">lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)</span><br></pre></td></tr></table></figure><p><strong>为什么需要多种颜色空间？</strong></p><ul><li>RGB：显示器友好，但对光照敏感</li><li>HSV：做颜色分割最好用（比如检测红色物体）</li><li>LAB：计算颜色差异时最准确</li></ul><hr><h2 id="二、传统图像处理操作"><a href="#二、传统图像处理操作" class="headerlink" title="二、传统图像处理操作"></a>二、传统图像处理操作</h2><p>虽然深度学习已经替代了很多传统方法，但这些基础操作用来预处理数据、理解原理仍然很重要。</p><h3 id="2-1-滤波与去噪"><a href="#2-1-滤波与去噪" class="headerlink" title="2.1 滤波与去噪"></a>2.1 滤波与去噪</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 均值滤波（模糊）</span></span><br><span class="line">blurred = cv2.blur(img, (<span class="number">5</span>, <span class="number">5</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 高斯滤波（权重更自然）</span></span><br><span class="line">gaussian = cv2.GaussianBlur(img, (<span class="number">5</span>, <span class="number">5</span>), sigmaX=<span class="number">1.0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 中值滤波（对椒盐噪声特别有效）</span></span><br><span class="line">median = cv2.medianBlur(img, <span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 双边滤波（保留边缘的平滑）</span></span><br><span class="line">bilateral = cv2.bilateralFilter(img, <span class="number">9</span>, <span class="number">75</span>, <span class="number">75</span>)</span><br></pre></td></tr></table></figure><h3 id="2-2-边缘检测"><a href="#2-2-边缘检测" class="headerlink" title="2.2 边缘检测"></a>2.2 边缘检测</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Canny 边缘检测（最经典）</span></span><br><span class="line">edges = cv2.Canny(img, threshold1=<span class="number">100</span>, threshold2=<span class="number">200</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Sobel 梯度（分别计算 x 和 y 方向）</span></span><br><span class="line">sobel_x = cv2.Sobel(gray, cv2.CV_64F, <span class="number">1</span>, <span class="number">0</span>, ksize=<span class="number">3</span>)</span><br><span class="line">sobel_y = cv2.Sobel(gray, cv2.CV_64F, <span class="number">0</span>, <span class="number">1</span>, ksize=<span class="number">3</span>)</span><br><span class="line">sobel_mag = np.sqrt(sobel_x**<span class="number">2</span> + sobel_y**<span class="number">2</span>)</span><br></pre></td></tr></table></figure><p>Canny 边缘检测的效果：（想象一下一张图片变成线稿的效果）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">原图           →       Canny 边缘</span><br><span class="line">┌─────────┐          ┌─────────────────┐</span><br><span class="line">│ 一只猫   │          │  ╱╲    ╱╲       │</span><br><span class="line">│ 坐在窗台 │   →      │ ╱  ╲  ╱  ╲      │</span><br><span class="line">│ 上晒太阳 │          ││    ████    │     │</span><br><span class="line">└─────────┘          └─────────────────┘</span><br></pre></td></tr></table></figure><h3 id="2-3-形态学操作"><a href="#2-3-形态学操作" class="headerlink" title="2.3 形态学操作"></a>2.3 形态学操作</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">kernel = np.ones((<span class="number">5</span>, <span class="number">5</span>), np.uint8)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 腐蚀（消除边界点，缩小白色区域）</span></span><br><span class="line">eroded = cv2.erode(binary, kernel, iterations=<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 膨胀（扩大白色区域）</span></span><br><span class="line">dilated = cv2.dilate(binary, kernel, iterations=<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开运算（先腐蚀后膨胀 = 去除小噪点）</span></span><br><span class="line">opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 闭运算（先膨胀后腐蚀 = 填补小洞）</span></span><br><span class="line">closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)</span><br></pre></td></tr></table></figure><h3 id="2-4-图像变换"><a href="#2-4-图像变换" class="headerlink" title="2.4 图像变换"></a>2.4 图像变换</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 缩放</span></span><br><span class="line">resized = cv2.resize(img, (<span class="number">224</span>, <span class="number">224</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 旋转</span></span><br><span class="line">(h, w) = img.shape[:<span class="number">2</span>]</span><br><span class="line">center = (w // <span class="number">2</span>, h // <span class="number">2</span>)</span><br><span class="line">matrix = cv2.getRotationMatrix2D(center, <span class="number">45</span>, <span class="number">1.0</span>)  <span class="comment"># 旋转 45 度</span></span><br><span class="line">rotated = cv2.warpAffine(img, matrix, (w, h))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 仿射变换（通用矩阵变换）</span></span><br><span class="line">matrix = np.float32([[<span class="number">1</span>, <span class="number">0.2</span>, <span class="number">0</span>], [<span class="number">0.2</span>, <span class="number">1</span>, <span class="number">0</span>]])</span><br><span class="line">affined = cv2.warpAffine(img, matrix, (w, h))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 透视变换（校正倾斜拍摄的文档）</span></span><br><span class="line">pts1 = np.float32([[<span class="number">50</span>,<span class="number">50</span>], [<span class="number">200</span>,<span class="number">50</span>], [<span class="number">50</span>,<span class="number">200</span>], [<span class="number">200</span>,<span class="number">200</span>]])</span><br><span class="line">pts2 = np.float32([[<span class="number">0</span>,<span class="number">0</span>], [<span class="number">300</span>,<span class="number">0</span>], [<span class="number">0</span>,<span class="number">300</span>], [<span class="number">300</span>,<span class="number">300</span>]])</span><br><span class="line">matrix = cv2.getPerspectiveTransform(pts1, pts2)</span><br><span class="line">warped = cv2.warpPerspective(img, matrix, (<span class="number">300</span>, <span class="number">300</span>))</span><br></pre></td></tr></table></figure><hr><h2 id="三、特征提取：从手工特征到深度学习"><a href="#三、特征提取：从手工特征到深度学习" class="headerlink" title="三、特征提取：从手工特征到深度学习"></a>三、特征提取：从手工特征到深度学习</h2><h3 id="3-1-传统特征（深度学习之前）"><a href="#3-1-传统特征（深度学习之前）" class="headerlink" title="3.1 传统特征（深度学习之前）"></a>3.1 传统特征（深度学习之前）</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># SIFT 关键点检测（尺度不变特征变换）</span></span><br><span class="line">sift = cv2.SIFT_create()</span><br><span class="line">keypoints, descriptors = sift.detectAndCompute(gray, <span class="literal">None</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># ORB（更快但不那么鲁棒）</span></span><br><span class="line">orb = cv2.ORB_create()</span><br><span class="line">keypoints_orb, descriptors_orb = orb.detectAndCompute(gray, <span class="literal">None</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在图像上画关键点</span></span><br><span class="line">img_kp = cv2.drawKeypoints(img, keypoints, <span class="literal">None</span>)</span><br></pre></td></tr></table></figure><p>SIFT 能检测出<strong>对旋转、缩放、光照都不敏感</strong>的关键点——这也正是 CNN 卷积核在做的事，只不过 CNN 用学习的方式找出了更好的特征。</p><h3 id="3-2-深度学习特征"><a href="#3-2-深度学习特征" class="headerlink" title="3.2 深度学习特征"></a>3.2 深度学习特征</h3><p>CNN 的每一层都在提取不同层次的”特征”：</p><table><thead><tr><th align="center">卷积层</th><th>学到的特征</th><th align="center">可视化</th></tr></thead><tbody><tr><td align="center">Layer 1</td><td>边缘、颜色、纹理</td><td align="center">▓ ▒ ░</td></tr><tr><td align="center">Layer 2</td><td>角点、弧线、简单形状</td><td align="center">⬡ ◇ ○</td></tr><tr><td align="center">Layer 3</td><td>眼睛、轮子、窗口（物体部件）</td><td align="center">👁 ⚙ 🪟</td></tr><tr><td align="center">Layer 4+</td><td>人脸、汽车、建筑（完整物体）</td><td align="center">🚗 🏠 👤</td></tr></tbody></table><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 用预训练 ResNet 提取特征</span></span><br><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> models, transforms</span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载预训练模型（去掉最后的分类层）</span></span><br><span class="line">resnet = models.resnet50(pretrained=<span class="literal">True</span>)</span><br><span class="line">feature_extractor = nn.Sequential(*<span class="built_in">list</span>(resnet.children())[:-<span class="number">1</span>])  <span class="comment"># 去掉全连接层</span></span><br><span class="line">feature_extractor.<span class="built_in">eval</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 预处理</span></span><br><span class="line">transform = transforms.Compose([</span><br><span class="line">    transforms.Resize(<span class="number">256</span>),</span><br><span class="line">    transforms.CenterCrop(<span class="number">224</span>),</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(mean=[<span class="number">0.485</span>, <span class="number">0.456</span>, <span class="number">0.406</span>], std=[<span class="number">0.229</span>, <span class="number">0.224</span>, <span class="number">0.225</span>]),</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">img = Image.<span class="built_in">open</span>(<span class="string">&#x27;example.jpg&#x27;</span>)</span><br><span class="line">input_tensor = transform(img).unsqueeze(<span class="number">0</span>)  <span class="comment"># [1, 3, 224, 224]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 提取特征</span></span><br><span class="line"><span class="keyword">with</span> torch.no_grad():</span><br><span class="line">    features = feature_extractor(input_tensor)  <span class="comment"># [1, 2048, 1, 1]</span></span><br><span class="line"></span><br><span class="line">feature_vector = features.squeeze().numpy()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;特征向量维度: <span class="subst">&#123;feature_vector.shape&#125;</span>&quot;</span>)  <span class="comment"># (2048,)</span></span><br></pre></td></tr></table></figure><p>这个 2048 维的向量就是 ResNet 对这张图片的”理解”——两张内容相似的图片，特征向量的距离应该很近。</p><hr><h2 id="四、CV-任务全景"><a href="#四、CV-任务全景" class="headerlink" title="四、CV 任务全景"></a>四、CV 任务全景</h2><h3 id="4-1-六大核心任务"><a href="#4-1-六大核心任务" class="headerlink" title="4.1 六大核心任务"></a>4.1 六大核心任务</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">计算机视觉</span><br><span class="line">├── 图像分类         ─── &quot;这是什么？&quot;</span><br><span class="line">│    └── ResNet、EfficientNet、ViT</span><br><span class="line">├── 目标检测         ─── &quot;东西在哪？&quot;</span><br><span class="line">│    └── YOLO、Faster R-CNN、DETR</span><br><span class="line">├── 语义分割         ─── &quot;每个像素属于什么？&quot;</span><br><span class="line">│    └── U-Net、DeepLab</span><br><span class="line">├── 实例分割         ─── &quot;每个物体的轮廓？&quot;</span><br><span class="line">│    └── Mask R-CNN</span><br><span class="line">├── 关键点检测       ─── &quot;关节在哪？&quot;</span><br><span class="line">│    └── OpenPose、HRNet</span><br><span class="line">└── 图像生成         ─── &quot;画一张图&quot;</span><br><span class="line">     └── GAN、Stable Diffusion、DALL·E</span><br></pre></td></tr></table></figure><h3 id="4-2-常用数据集"><a href="#4-2-常用数据集" class="headerlink" title="4.2 常用数据集"></a>4.2 常用数据集</h3><table><thead><tr><th align="center">数据集</th><th align="center">任务</th><th align="center">规模</th><th align="center">指标</th></tr></thead><tbody><tr><td align="center">ImageNet</td><td align="center">分类</td><td align="center">1400万张，1000类</td><td align="center">Top-1 &#x2F; Top-5</td></tr><tr><td align="center">COCO</td><td align="center">检测+分割</td><td align="center">33万张，80类</td><td align="center">mAP</td></tr><tr><td align="center">CIFAR-10&#x2F;100</td><td align="center">分类</td><td align="center">6万张，10&#x2F;100类</td><td align="center">Accuracy</td></tr><tr><td align="center">MNIST</td><td align="center">分类</td><td align="center">7万张，10类</td><td align="center">Accuracy</td></tr><tr><td align="center">Cityscapes</td><td align="center">语义分割</td><td align="center">5000张街景</td><td align="center">mIoU</td></tr></tbody></table><h3 id="4-3-CV-领域的”ImageNet-时刻”"><a href="#4-3-CV-领域的”ImageNet-时刻”" class="headerlink" title="4.3 CV 领域的”ImageNet 时刻”"></a>4.3 CV 领域的”ImageNet 时刻”</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">AlexNet (2012) → 超越传统方法，深度学习时代开启</span><br><span class="line">VGG (2014) → 更深的网络，模块化设计</span><br><span class="line">ResNet (2015) → 残差连接，152 层也训得动</span><br><span class="line">YOLO (2016) → 实时目标检测</span><br><span class="line">GAN (2014-2018) → 图像生成</span><br><span class="line">ViT (2020) → Transformer 打败 CNN</span><br><span class="line">CLIP (2021) → 图文多模态</span><br><span class="line">SAM (2023) → 通用分割模型</span><br><span class="line">Stable Diffusion (2022-2026) → 文生图主流</span><br></pre></td></tr></table></figure><hr><h2 id="五、数据增强"><a href="#五、数据增强" class="headerlink" title="五、数据增强"></a>五、数据增强</h2><p>数据增强是 CV 项目中最有效的”免费午餐”——不需要新数据，通过变换现有数据来提升泛化能力。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> transforms</span><br><span class="line"></span><br><span class="line">train_transform = transforms.Compose([</span><br><span class="line">    transforms.RandomResizedCrop(<span class="number">224</span>),       <span class="comment"># 随机裁剪和缩放</span></span><br><span class="line">    transforms.RandomHorizontalFlip(),        <span class="comment"># 随机水平翻转</span></span><br><span class="line">    transforms.ColorJitter(<span class="number">0.2</span>, <span class="number">0.2</span>, <span class="number">0.2</span>),   <span class="comment"># 随机颜色变化</span></span><br><span class="line">    transforms.RandomAffine(degrees=<span class="number">10</span>,       <span class="comment"># 随机旋转+平移</span></span><br><span class="line">                            translate=(<span class="number">0.1</span>, <span class="number">0.1</span>)),</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(mean=[<span class="number">0.485</span>, <span class="number">0.456</span>, <span class="number">0.406</span>],</span><br><span class="line">                         std=[<span class="number">0.229</span>, <span class="number">0.224</span>, <span class="number">0.225</span>]),</span><br><span class="line">])</span><br></pre></td></tr></table></figure><p><strong>常用增强策略：</strong></p><ul><li>几何变换：翻转、旋转、裁剪、缩放</li><li>颜色变换：亮度、对比度、饱和度</li><li>噪声：高斯噪声、椒盐噪声</li><li>高级：Cutout（随机遮挡）、MixUp（混合两张图）、CutMix</li></ul><hr><h2 id="六、总结"><a href="#六、总结" class="headerlink" title="六、总结"></a>六、总结</h2><table><thead><tr><th>知识点</th><th align="center">掌握</th></tr></thead><tbody><tr><td>图像在计算机中的表示（RGB&#x2F;灰度&#x2F;H×W×C）</td><td align="center">✅</td></tr><tr><td>OpenCV 基础操作（滤波&#x2F;边缘&#x2F;形态学）</td><td align="center">✅</td></tr><tr><td>传统特征 vs 深度学习特征</td><td align="center">✅</td></tr><tr><td>用预训练 CNN 提取特征向量</td><td align="center">✅</td></tr><tr><td>CV 六大任务与经典模型</td><td align="center">✅</td></tr><tr><td>数据增强方法与策略</td><td align="center">✅</td></tr></tbody></table><p><strong>下一步推荐：</strong></p><ul><li><a href="/2026/07/03/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BBCIFAR-10/">实战：图像分类（CIFAR-10）</a>（即将发布）</li><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN 卷积神经网络</a></li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/</id>
    <link href="https://aijvs.com/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/"/>
    <published>2026-07-03T08:00:00.000Z</published>
    <summary>计算机视觉入门教程：OpenCV 图像读取、滤波、边缘检测、特征提取，以及 CNN 时代的视觉任务全景。</summary>
    <title>计算机视觉入门：图像处理基础</title>
    <updated>2026-07-03T08:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="深度学习" scheme="https://aijvs.com/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"/>
    <category term="自然语言处理" scheme="https://aijvs.com/tags/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86/"/>
    <category term="进阶教程" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/"/>
    <category term="LSTM" scheme="https://aijvs.com/tags/LSTM/"/>
    <category term="RNN" scheme="https://aijvs.com/tags/RNN/"/>
    <category term="序列模型" scheme="https://aijvs.com/tags/%E5%BA%8F%E5%88%97%E6%A8%A1%E5%9E%8B/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>CNN 处理的是图片——有空间结构。那<strong>文本、语音、股价、视频</strong>呢？这些是序列数据，长度不固定，前后有依赖关系。</p><blockquote><p>“I <strong>love</strong> this movie” 和 “I don’t <strong>love</strong> this movie”——同一个词 “love”，因为前面有个 “don’t”，意思完全反了。</p></blockquote><p><strong>RNN（循环神经网络）</strong> 就是为序列数据设计的——它能记住前面看到的信息来影响当前的判断。</p><p>但 RNN 有个致命缺陷：<strong>长期依赖问题</strong>——看了 100 个词之后，第 1 个词的信息基本被遗忘了。这就是 <strong>LSTM（长短期记忆网络）</strong> 要解决的问题。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/05/25/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97%EF%BC%9A%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%90%86%E8%A7%A3%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">深度学习入门指南：从零开始理解神经网络</a></li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li></ul><p>理解神经网络的基本概念就够了。</p><hr><h2 id="一、为什么需要-RNN？"><a href="#一、为什么需要-RNN？" class="headerlink" title="一、为什么需要 RNN？"></a>一、为什么需要 RNN？</h2><h3 id="传统网络的问题"><a href="#传统网络的问题" class="headerlink" title="传统网络的问题"></a>传统网络的问题</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">传统神经网络（全连接 / CNN）:</span><br><span class="line">输入 → [网络] → 输出</span><br><span class="line"></span><br><span class="line">每个输入独立处理，没有&quot;记忆&quot;能力。</span><br><span class="line">&quot;I am from China, I speak ______&quot;</span><br><span class="line">→ 需要记住前面说了 &quot;China&quot; 才能预测 &quot;Chinese&quot;</span><br><span class="line">→ 传统网络做不到</span><br></pre></td></tr></table></figure><h3 id="RNN-的核心思想"><a href="#RNN-的核心思想" class="headerlink" title="RNN 的核心思想"></a>RNN 的核心思想</h3><p><strong>循环</strong>：网络在处理每个输入时，不仅看当前输入，还看上一步的隐藏状态。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">RNN:</span><br><span class="line">               输出1      输出2      输出3</span><br><span class="line">                ↑         ↑         ↑</span><br><span class="line">     ┌───┐     ┌───┐     ┌───┐     ┌───┐</span><br><span class="line">输入 →│ A │────▶│ A │────▶│ A │────▶│ A │</span><br><span class="line">     └───┘     └─┬─┘     └─┬─┘     └─┬─┘</span><br><span class="line">       ↑         │         │         │</span><br><span class="line">       └─────────┴─────────┴─────────┘</span><br><span class="line">       隐藏状态在时间步之间传递</span><br></pre></td></tr></table></figure><hr><h2 id="二、RNN-原理"><a href="#二、RNN-原理" class="headerlink" title="二、RNN 原理"></a>二、RNN 原理</h2><h3 id="2-1-数学表达"><a href="#2-1-数学表达" class="headerlink" title="2.1 数学表达"></a>2.1 数学表达</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">h_t = tanh(W_ih · x_t + W_hh · h_&#123;t-1&#125; + b)</span><br><span class="line">y_t = W_hy · h_t + b_y</span><br><span class="line"></span><br><span class="line">其中：</span><br><span class="line">h_t    = 时间步 t 的隐藏状态</span><br><span class="line">x_t    = 时间步 t 的输入</span><br><span class="line">h_&#123;t-1&#125;= 上一步的隐藏状态（记忆）</span><br><span class="line">tanh   = 激活函数（压缩到 [-1, 1]）</span><br></pre></td></tr></table></figure><h3 id="2-2-PyTorch-实现"><a href="#2-2-PyTorch-实现" class="headerlink" title="2.2 PyTorch 实现"></a>2.2 PyTorch 实现</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"></span><br><span class="line"><span class="comment"># PyTorch 内置 RNN 层</span></span><br><span class="line">rnn = nn.RNN(</span><br><span class="line">    input_size=<span class="number">100</span>,    <span class="comment"># 每个时间步的输入维度（如词向量维度）</span></span><br><span class="line">    hidden_size=<span class="number">128</span>,   <span class="comment"># 隐藏状态维度</span></span><br><span class="line">    num_layers=<span class="number">2</span>,      <span class="comment"># 层数</span></span><br><span class="line">    batch_first=<span class="literal">True</span>,  <span class="comment"># 输入形状: (batch, seq_len, input_size)</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输入: [batch=16, seq_len=10, input_size=100]</span></span><br><span class="line">x = torch.randn(<span class="number">16</span>, <span class="number">10</span>, <span class="number">100</span>)</span><br><span class="line">output, h_n = rnn(x)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;输出形状: <span class="subst">&#123;output.shape&#125;</span>&quot;</span>)  <span class="comment"># [16, 10, 128] — 每个时间步的隐藏状态</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;最终隐藏状态: <span class="subst">&#123;h_n.shape&#125;</span>&quot;</span>)  <span class="comment"># [2, 16, 128] — 最后一层的最终状态</span></span><br></pre></td></tr></table></figure><h3 id="2-3-手写一个简易-RNN"><a href="#2-3-手写一个简易-RNN" class="headerlink" title="2.3 手写一个简易 RNN"></a>2.3 手写一个简易 RNN</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">SimpleRNN</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;手动实现的单层 RNN&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, input_size, hidden_size</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.hidden_size = hidden_size</span><br><span class="line">        <span class="variable language_">self</span>.i2h = nn.Linear(input_size + hidden_size, hidden_size)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, hidden=<span class="literal">None</span></span>):</span><br><span class="line">        batch_size, seq_len, _ = x.shape</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> hidden <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            hidden = torch.zeros(<span class="number">1</span>, batch_size, <span class="variable language_">self</span>.hidden_size).to(x.device)</span><br><span class="line"></span><br><span class="line">        outputs = []</span><br><span class="line">        <span class="keyword">for</span> t <span class="keyword">in</span> <span class="built_in">range</span>(seq_len):</span><br><span class="line">            combined = torch.cat((x[:, t, :], hidden.squeeze(<span class="number">0</span>)), dim=<span class="number">1</span>)</span><br><span class="line">            hidden = torch.tanh(<span class="variable language_">self</span>.i2h(combined)).unsqueeze(<span class="number">0</span>)</span><br><span class="line">            outputs.append(hidden)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> torch.stack(outputs, dim=<span class="number">1</span>).squeeze(<span class="number">0</span>), hidden</span><br></pre></td></tr></table></figure><hr><h2 id="三、RNN-的致命问题：梯度消失"><a href="#三、RNN-的致命问题：梯度消失" class="headerlink" title="三、RNN 的致命问题：梯度消失"></a>三、RNN 的致命问题：梯度消失</h2><h3 id="3-1-问题根源"><a href="#3-1-问题根源" class="headerlink" title="3.1 问题根源"></a>3.1 问题根源</h3><p>RNN 在每个时间步都要乘以权重 <code>W_hh</code>。经过 T 个时间步：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">∂L/∂W ∝ W_hh^T</span><br></pre></td></tr></table></figure><ul><li>如果 <code>W_hh</code> 的特征值 &lt; 1：<strong>梯度消失</strong> — 远程信息完全被遗忘</li><li>如果 <code>W_hh</code> 的特征值 &gt; 1：<strong>梯度爆炸</strong> — 训练不稳定</li></ul><p><strong>结果：</strong> 标准 RNN 实际上只能记住大约 7-10 步之前的信息。</p><h3 id="3-2-梯度消失的直观感受"><a href="#3-2-梯度消失的直观感受" class="headerlink" title="3.2 梯度消失的直观感受"></a>3.2 梯度消失的直观感受</h3><blockquote><p>读一段 100 个字的文章，读到第 100 个字时，第 1 个字的信息已经被稀释了 2^100 倍——远小于噪声。</p></blockquote><hr><h2 id="四、LSTM：长短期记忆网络"><a href="#四、LSTM：长短期记忆网络" class="headerlink" title="四、LSTM：长短期记忆网络"></a>四、LSTM：长短期记忆网络</h2><p>LSTM（Long Short-Term Memory）通过<strong>门控机制</strong>解决了梯度消失问题。它引入了三个门和一个细胞状态：</p><h3 id="4-1-LSTM-内部结构"><a href="#4-1-LSTM-内部结构" class="headerlink" title="4.1 LSTM 内部结构"></a>4.1 LSTM 内部结构</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">                   ┌───────────────────────────┐</span><br><span class="line">                   │        LSTM 单元           │</span><br><span class="line">                   │                           │</span><br><span class="line">h_&#123;t-1&#125; ──────────┬─▶┌─────┐    ┌─────┐      │</span><br><span class="line">                   │  │遗忘门│    │输入门│      │</span><br><span class="line">x_t ───────────────┼─▶└─────┘    └─────┘      │</span><br><span class="line">                   │     │          │          │</span><br><span class="line">                   │     ▼          ▼          │</span><br><span class="line">                   │  ┌─────────────────┐      │</span><br><span class="line">                   │  │     更新细胞状态  │      │</span><br><span class="line">                   │  └─────────────────┘      │</span><br><span class="line">                   │         │                 │</span><br><span class="line">                   │         ▼                 │</span><br><span class="line">                   │     ┌─────┐              │</span><br><span class="line">                   │     │输出门│              │</span><br><span class="line">                   │     └─────┘              │</span><br><span class="line">                   │         │                 │</span><br><span class="line">                   │    h_t, c_t               │</span><br><span class="line">                   └───────────────────────────┘</span><br></pre></td></tr></table></figure><p><strong>四个组件的作用：</strong></p><table><thead><tr><th>组件</th><th>公式</th><th>作用</th></tr></thead><tbody><tr><td><strong>遗忘门</strong></td><td>f_t &#x3D; σ(W_f · [h_{t-1}, x_t] + b_f)</td><td>决定丢弃哪些旧的记忆</td></tr><tr><td><strong>输入门</strong></td><td>i_t &#x3D; σ(W_i · [h_{t-1}, x_t] + b_i)</td><td>决定存入哪些新信息</td></tr><tr><td><strong>候选记忆</strong></td><td>Ĉ_t &#x3D; tanh(W_c · [h_{t-1}, x_t] + b_c)</td><td>生成新的候选记忆</td></tr><tr><td><strong>输出门</strong></td><td>o_t &#x3D; σ(W_o · [h_{t-1}, x_t] + b_o)</td><td>决定输出哪些记忆</td></tr></tbody></table><p>状态更新：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">C_t = f_t ⊙ C_&#123;t-1&#125; + i_t ⊙ Ĉ_t    # 遗忘旧记忆 + 添加新记忆</span><br><span class="line">h_t = o_t ⊙ tanh(C_t)                # 基于细胞状态输出</span><br></pre></td></tr></table></figure><p><strong>关键创新</strong>：细胞状态 C_t 的更新是<strong>加法</strong>而非乘法，梯度沿 C_t 传播时不会指数衰减——这就是 LSTM 能记住长程依赖的原因。</p><h3 id="4-2-为什么-LSTM-比-RNN-好？"><a href="#4-2-为什么-LSTM-比-RNN-好？" class="headerlink" title="4.2 为什么 LSTM 比 RNN 好？"></a>4.2 为什么 LSTM 比 RNN 好？</h3><table><thead><tr><th align="center">RNN</th><th align="center">LSTM</th></tr></thead><tbody><tr><td align="center">一个 tanh 层</td><td align="center">三个 σ 层 + 一个 tanh 层</td></tr><tr><td align="center">梯度沿时间步乘法传播 → 指数衰减</td><td align="center">梯度沿细胞状态加法传播 → 稳定</td></tr><tr><td align="center">有效记忆 ~10 步</td><td align="center">有效记忆 ~100+ 步</td></tr><tr><td align="center">几乎被淘汰</td><td align="center">仍是工业标准之一</td></tr></tbody></table><blockquote><p>2015 年后，LSTM 在大部分任务上又被 <strong>Transformer</strong> 超越（尤其 NLP）。但在时间序列预测、语音等任务上，LSTM 依然能打。</p></blockquote><hr><h2 id="五、实战：情感分析"><a href="#五、实战：情感分析" class="headerlink" title="五、实战：情感分析"></a>五、实战：情感分析</h2><p>我们用 LSTM 对 IMDB 影评做二分类（正面&#x2F;负面）。</p><h3 id="5-1-数据准备"><a href="#5-1-数据准备" class="headerlink" title="5.1 数据准备"></a>5.1 数据准备</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">import</span> torch.optim <span class="keyword">as</span> optim</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torch.nn.utils.rnn <span class="keyword">import</span> pad_sequence, pack_padded_sequence, pad_packed_sequence</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> torchtext.datasets <span class="keyword">import</span> IMDB</span><br><span class="line"><span class="keyword">from</span> torchtext.data.utils <span class="keyword">import</span> get_tokenizer</span><br><span class="line"><span class="keyword">from</span> torchtext.vocab <span class="keyword">import</span> build_vocab_from_iterator</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;设备: <span class="subst">&#123;device&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 文本预处理</span></span><br><span class="line">tokenizer = get_tokenizer(<span class="string">&#x27;basic_english&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">yield_tokens</span>(<span class="params">data_iter</span>):</span><br><span class="line">    <span class="keyword">for</span> label, line <span class="keyword">in</span> data_iter:</span><br><span class="line">        <span class="keyword">yield</span> tokenizer(line)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载训练数据</span></span><br><span class="line">train_iter = IMDB(split=<span class="string">&#x27;train&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 构建词表（只保留最常见的 25000 个词）</span></span><br><span class="line">vocab = build_vocab_from_iterator(</span><br><span class="line">    yield_tokens(train_iter),</span><br><span class="line">    specials=[<span class="string">&#x27;&lt;unk&gt;&#x27;</span>, <span class="string">&#x27;&lt;pad&gt;&#x27;</span>, <span class="string">&#x27;&lt;bos&gt;&#x27;</span>],</span><br><span class="line">    max_tokens=<span class="number">25000</span></span><br><span class="line">)</span><br><span class="line">vocab.set_default_index(vocab[<span class="string">&#x27;&lt;unk&gt;&#x27;</span>])</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;词表大小: <span class="subst">&#123;<span class="built_in">len</span>(vocab)&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 文本 → 索引序列</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">encode_text</span>(<span class="params">text, max_len=<span class="number">200</span></span>):</span><br><span class="line">    tokens = tokenizer(text)[:max_len]</span><br><span class="line">    <span class="keyword">return</span> torch.tensor([vocab[token] <span class="keyword">for</span> token <span class="keyword">in</span> tokens], dtype=torch.long)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 准备数据集</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">IMDBDataset</span>(torch.utils.data.Dataset):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, split, max_len=<span class="number">200</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.data = <span class="built_in">list</span>(IMDB(split=split))</span><br><span class="line">        <span class="variable language_">self</span>.max_len = max_len</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__len__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">len</span>(<span class="variable language_">self</span>.data)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__getitem__</span>(<span class="params">self, idx</span>):</span><br><span class="line">        label, text = <span class="variable language_">self</span>.data[idx]</span><br><span class="line">        label = <span class="number">1</span> <span class="keyword">if</span> label == <span class="string">&#x27;pos&#x27;</span> <span class="keyword">else</span> <span class="number">0</span></span><br><span class="line">        tokens = encode_text(text, <span class="variable language_">self</span>.max_len)</span><br><span class="line">        <span class="keyword">return</span> tokens, label</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">collate_batch</span>(<span class="params">batch</span>):</span><br><span class="line">    texts, labels = <span class="built_in">zip</span>(*batch)</span><br><span class="line">    lengths = torch.tensor([<span class="built_in">len</span>(t) <span class="keyword">for</span> t <span class="keyword">in</span> texts])</span><br><span class="line">    padded = pad_sequence(texts, batch_first=<span class="literal">True</span>, padding_value=vocab[<span class="string">&#x27;&lt;pad&gt;&#x27;</span>])</span><br><span class="line">    <span class="keyword">return</span> padded, torch.tensor(labels, dtype=torch.long), lengths</span><br><span class="line"></span><br><span class="line">train_dataset = IMDBDataset(<span class="string">&#x27;train&#x27;</span>)</span><br><span class="line">test_dataset = IMDBDataset(<span class="string">&#x27;test&#x27;</span>)</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(train_dataset, batch_size=<span class="number">64</span>, shuffle=<span class="literal">True</span>, collate_fn=collate_batch)</span><br><span class="line">test_loader = DataLoader(test_dataset, batch_size=<span class="number">64</span>, shuffle=<span class="literal">False</span>, collate_fn=collate_batch)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;训练集: <span class="subst">&#123;<span class="built_in">len</span>(train_dataset)&#125;</span> 条&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;测试集: <span class="subst">&#123;<span class="built_in">len</span>(test_dataset)&#125;</span> 条&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="5-2-定义-LSTM-模型"><a href="#5-2-定义-LSTM-模型" class="headerlink" title="5.2 定义 LSTM 模型"></a>5.2 定义 LSTM 模型</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LSTMClassifier</span>(nn.Module):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, vocab_size, embed_dim=<span class="number">100</span>, hidden_dim=<span class="number">128</span>, num_layers=<span class="number">2</span>, num_classes=<span class="number">2</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=vocab[<span class="string">&#x27;&lt;pad&gt;&#x27;</span>])</span><br><span class="line">        <span class="variable language_">self</span>.lstm = nn.LSTM(</span><br><span class="line">            input_size=embed_dim,</span><br><span class="line">            hidden_size=hidden_dim,</span><br><span class="line">            num_layers=num_layers,</span><br><span class="line">            batch_first=<span class="literal">True</span>,</span><br><span class="line">            dropout=<span class="number">0.3</span> <span class="keyword">if</span> num_layers &gt; <span class="number">1</span> <span class="keyword">else</span> <span class="number">0</span>,</span><br><span class="line">            bidirectional=<span class="literal">False</span></span><br><span class="line">        )</span><br><span class="line">        <span class="variable language_">self</span>.dropout = nn.Dropout(<span class="number">0.3</span>)</span><br><span class="line">        <span class="variable language_">self</span>.fc = nn.Linear(hidden_dim, num_classes)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x, lengths=<span class="literal">None</span></span>):</span><br><span class="line">        <span class="comment"># x: [batch, seq_len]</span></span><br><span class="line">        embedded = <span class="variable language_">self</span>.embedding(x)  <span class="comment"># [batch, seq_len, embed_dim]</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># 使用 pack_padded_sequence 避免填充部分被处理</span></span><br><span class="line">        <span class="keyword">if</span> lengths <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">            lengths = lengths.cpu()</span><br><span class="line">            packed = pack_padded_sequence(embedded, lengths, batch_first=<span class="literal">True</span>, enforce_sorted=<span class="literal">False</span>)</span><br><span class="line">            _, (hidden, cell) = <span class="variable language_">self</span>.lstm(packed)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            _, (hidden, cell) = <span class="variable language_">self</span>.lstm(embedded)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 取最后一层的最后一个时间步的隐藏状态</span></span><br><span class="line">        last_hidden = hidden[-<span class="number">1</span>]  <span class="comment"># [batch, hidden_dim]</span></span><br><span class="line"></span><br><span class="line">        out = <span class="variable language_">self</span>.dropout(last_hidden)</span><br><span class="line">        out = <span class="variable language_">self</span>.fc(out)  <span class="comment"># [batch, num_classes]</span></span><br><span class="line">        <span class="keyword">return</span> out</span><br></pre></td></tr></table></figure><h3 id="5-3-训练"><a href="#5-3-训练" class="headerlink" title="5.3 训练"></a>5.3 训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">model = LSTMClassifier(<span class="built_in">len</span>(vocab)).to(device)</span><br><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line">optimizer = optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line"></span><br><span class="line">EPOCHS = <span class="number">5</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(EPOCHS):</span><br><span class="line">    model.train()</span><br><span class="line">    total_loss = <span class="number">0</span></span><br><span class="line">    correct = <span class="number">0</span></span><br><span class="line">    total = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> texts, labels, lengths <span class="keyword">in</span> train_loader:</span><br><span class="line">        texts, labels = texts.to(device), labels.to(device)</span><br><span class="line"></span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        output = model(texts, lengths)</span><br><span class="line">        loss = criterion(output, labels)</span><br><span class="line">        loss.backward()</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 梯度裁剪：防止梯度爆炸</span></span><br><span class="line">        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=<span class="number">1.0</span>)</span><br><span class="line"></span><br><span class="line">        optimizer.step()</span><br><span class="line"></span><br><span class="line">        total_loss += loss.item()</span><br><span class="line">        _, preds = output.<span class="built_in">max</span>(<span class="number">1</span>)</span><br><span class="line">        total += labels.size(<span class="number">0</span>)</span><br><span class="line">        correct += preds.eq(labels).<span class="built_in">sum</span>().item()</span><br><span class="line"></span><br><span class="line">    train_acc = <span class="number">100.</span> * correct / total</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 测试</span></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    test_correct = <span class="number">0</span></span><br><span class="line">    test_total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> texts, labels, lengths <span class="keyword">in</span> test_loader:</span><br><span class="line">            texts, labels = texts.to(device), labels.to(device)</span><br><span class="line">            _, preds = model(texts, lengths).<span class="built_in">max</span>(<span class="number">1</span>)</span><br><span class="line">            test_total += labels.size(<span class="number">0</span>)</span><br><span class="line">            test_correct += preds.eq(labels).<span class="built_in">sum</span>().item()</span><br><span class="line"></span><br><span class="line">    test_acc = <span class="number">100.</span> * test_correct / test_total</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;Epoch <span class="subst">&#123;epoch+<span class="number">1</span>&#125;</span>/<span class="subst">&#123;EPOCHS&#125;</span> | Loss: <span class="subst">&#123;total_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span> | &#x27;</span></span><br><span class="line">          <span class="string">f&#x27;Train: <span class="subst">&#123;train_acc:<span class="number">.2</span>f&#125;</span>% | Test: <span class="subst">&#123;test_acc:<span class="number">.2</span>f&#125;</span>%&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;训练完成 ✅&quot;</span>)</span><br></pre></td></tr></table></figure><p>LSTM 情感分析模型通常 <strong>5 个 epoch 达到 85-88% 的测试准确率</strong>。</p><h3 id="5-4-推理示例"><a href="#5-4-推理示例" class="headerlink" title="5.4 推理示例"></a>5.4 推理示例</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">predict_sentiment</span>(<span class="params">text</span>):</span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        tokens = encode_text(text).unsqueeze(<span class="number">0</span>).to(device)</span><br><span class="line">        output = model(tokens)</span><br><span class="line">        prob = torch.softmax(output, dim=<span class="number">1</span>)</span><br><span class="line">        pred = output.argmax(dim=<span class="number">1</span>).item()</span><br><span class="line">        confidence = prob[<span class="number">0</span>][pred].item()</span><br><span class="line">        sentiment = <span class="string">&quot;正面&quot;</span> <span class="keyword">if</span> pred == <span class="number">1</span> <span class="keyword">else</span> <span class="string">&quot;负面&quot;</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;文本: <span class="subst">&#123;text[:<span class="number">50</span>]&#125;</span>...&quot;</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;情感: <span class="subst">&#123;sentiment&#125;</span> (置信度: <span class="subst">&#123;confidence:<span class="number">.2</span>%&#125;</span>)&quot;</span>)</span><br><span class="line">    <span class="keyword">return</span> pred</span><br><span class="line"></span><br><span class="line">predict_sentiment(<span class="string">&quot;This movie was absolutely amazing! The acting and plot were top-notch.&quot;</span>)</span><br><span class="line">predict_sentiment(<span class="string">&quot;Terrible waste of time. I regret watching this movie.&quot;</span>)</span><br></pre></td></tr></table></figure><p>输出示例：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">文本: This movie was absolutely amazing! The acting...</span><br><span class="line">情感: 正面 (置信度: 99.12%)</span><br><span class="line">文本: Terrible waste of time. I regret watching this...</span><br><span class="line">情感: 负面 (置信度: 98.45%)</span><br></pre></td></tr></table></figure><hr><h2 id="六、LSTM-vs-GRU-vs-Transformer"><a href="#六、LSTM-vs-GRU-vs-Transformer" class="headerlink" title="六、LSTM vs GRU vs Transformer"></a>六、LSTM vs GRU vs Transformer</h2><table><thead><tr><th align="center">模型</th><th align="center">参数量</th><th align="center">长期记忆</th><th align="center">并行化</th><th align="center">典型场景</th></tr></thead><tbody><tr><td align="center">RNN</td><td align="center">少</td><td align="center">❌</td><td align="center">❌</td><td align="center">已被淘汰</td></tr><tr><td align="center">LSTM</td><td align="center">中</td><td align="center">✅</td><td align="center">❌</td><td align="center">时间序列、语音</td></tr><tr><td align="center">GRU</td><td align="center">少（比 LSTM 少 1&#x2F;4）</td><td align="center">✅</td><td align="center">❌</td><td align="center">可替代 LSTM，效果相当</td></tr><tr><td align="center">Transformer</td><td align="center">多</td><td align="center">✅✅</td><td align="center">✅✅</td><td align="center">NLP 主流（BERT&#x2F;GPT）</td></tr></tbody></table><blockquote><p><strong>GRU（门控循环单元）</strong> 是 LSTM 的简化版——把遗忘门和输入门合并为”更新门”，去掉了细胞状态。效果和 LSTM 差不多，参数更少，训练更快。</p></blockquote><hr><h2 id="七、总结"><a href="#七、总结" class="headerlink" title="七、总结"></a>七、总结</h2><table><thead><tr><th>知识点</th><th align="center">掌握</th></tr></thead><tbody><tr><td>RNN 为什么需要”记忆”</td><td align="center">✅</td></tr><tr><td>RNN 的循环机制和梯度消失问题</td><td align="center">✅</td></tr><tr><td>LSTM 的遗忘门&#x2F;输入门&#x2F;输出门</td><td align="center">✅ <strong>核心</strong></td></tr><tr><td>LSTM 如何解决长期依赖（细胞状态加法更新）</td><td align="center">✅</td></tr><tr><td>PyTorch LSTM 情感分析实战</td><td align="center">✅ <strong>实战</strong></td></tr><tr><td>GRU &#x2F; Transformer 对比</td><td align="center">✅</td></tr></tbody></table><p><strong>下一步推荐：</strong></p><ul><li><a href="/2026/07/03/NLP%E5%85%A5%E9%97%A8%EF%BC%9A%E6%96%87%E6%9C%AC%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E8%AF%8D%E5%90%91%E9%87%8F/">NLP 入门：文本预处理与词向量</a>（即将发布）</li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E5%BC%A0%E9%87%8F%E6%93%8D%E4%BD%9C%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%BE%AE%E5%88%86/">PyTorch 实战（一）：张量操作与自动微分</a></li><li><a href="/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/">神经网络架构详解：CNN 卷积神经网络</a></li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ARNN%E4%B8%8ELSTM/</id>
    <link href="https://aijvs.com/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ARNN%E4%B8%8ELSTM/"/>
    <published>2026-07-03T07:00:00.000Z</published>
    <summary>RNN 循环神经网络与 LSTM 长短期记忆网络的完整教程：原理、梯度消失、门控机制与 PyTorch 情感分析实战。</summary>
    <title>神经网络架构详解：RNN 与 LSTM</title>
    <updated>2026-07-03T07:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>AIJVS Team</name>
    </author>
    <category term="深度学习" scheme="https://aijvs.com/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"/>
    <category term="PyTorch" scheme="https://aijvs.com/tags/PyTorch/"/>
    <category term="进阶教程" scheme="https://aijvs.com/tags/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/"/>
    <category term="卷积神经网络" scheme="https://aijvs.com/tags/%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
    <category term="计算机视觉" scheme="https://aijvs.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"/>
    <category term="CNN" scheme="https://aijvs.com/tags/CNN/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>上一篇文章我们用全连接网络实现了手写数字识别——但你知道吗？如果换成人脸识别、自动驾驶场景，全连接网络基本不 work。</p><p>原因很简单：<strong>全连接把 28×28 的图片展平成 784 个独立的像素，完全丢掉了空间结构信息。</strong> 一张猫的图片，把像素随机打乱，全连接网络认不出来了。</p><p><strong>CNN（卷积神经网络）</strong> 就是来解决这个问题的——它用卷积核在图片上滑动，保留空间结构，捕捉局部特征。这也是为什么 CNN 统治了计算机视觉领域近十年。</p><hr><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><ul><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9A%E6%9E%84%E5%BB%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C/">PyTorch 实战（二）：构建第一个全连接网络</a></li><li><a href="/2026/06/17/AI%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0%E2%80%94%E2%80%94%E8%AE%A9%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%BC%9A%E7%9C%8B%E5%90%91%E9%87%8F/">AI数学基础（一）：线性代数——让机器学会看向量</a></li></ul><p>需要已经会用 PyTorch 搭网络、跑训练循环。</p><hr><h2 id="一、CNN-的核心思想"><a href="#一、CNN-的核心思想" class="headerlink" title="一、CNN 的核心思想"></a>一、CNN 的核心思想</h2><h3 id="为什么全连接不行？"><a href="#为什么全连接不行？" class="headerlink" title="为什么全连接不行？"></a>为什么全连接不行？</h3><p>全连接层的参数量 &#x3D; 输入维度 × 输出维度。对于一张 256×256 的彩色图片：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 256 × 256 × 3 = 196,608</span><br><span class="line">全连接层（128个神经元）: 196,608 × 128 ≈ 2500 万参数</span><br></pre></td></tr></table></figure><p><strong>2500 万个参数就一层！</strong> 三层下去直接上亿，根本训不动。</p><h3 id="CNN-的三大优势"><a href="#CNN-的三大优势" class="headerlink" title="CNN 的三大优势"></a>CNN 的三大优势</h3><table><thead><tr><th>全连接</th><th>CNN</th></tr></thead><tbody><tr><td>每个像素独立</td><td><strong>局部连接</strong> — 只关注局部区域</td></tr><tr><td>不同位置要重复学习</td><td><strong>权值共享</strong> — 同一个卷积核扫过整张图</td></tr><tr><td>参数量爆炸</td><td><strong>参数量可控</strong> — 取决于卷积核大小而非图片大小</td></tr></tbody></table><hr><h2 id="二、卷积层详解"><a href="#二、卷积层详解" class="headerlink" title="二、卷积层详解"></a>二、卷积层详解</h2><h3 id="2-1-卷积操作"><a href="#2-1-卷积操作" class="headerlink" title="2.1 卷积操作"></a>2.1 卷积操作</h3><p>想象你在图片上放了一个小窗口（3×3 像素），窗口在每个位置都和图片做<strong>点积运算</strong>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">输入图片 (5×5)          卷积核 (3×3)          输出特征图 (3×3)</span><br><span class="line">┌──┬──┬──┬──┬──┐       ┌──┬──┬──┐          ┌───┬───┬───┐</span><br><span class="line">│1 │2 │3 │4 │5 │       │1 │0 │-1│          │ ? │ ? │ ? │</span><br><span class="line">├──┼──┼──┼──┼──┤       ├──┼──┼──┤          ├───┼───┼───┤</span><br><span class="line">│6 │7 │8 │9 │10│       │2 │0 │-2│          │ ? │ ? │ ? │</span><br><span class="line">├──┼──┼──┼──┼──┤       ├──┼──┼──┤          ├───┼───┼───┤</span><br><span class="line">│11│12│13│14│15│       │1 │0 │-1│          │ ? │ ? │ ? │</span><br><span class="line">├──┼──┼──┼──┼──┤       └──┴──┴──┘          └───┴───┴───┘</span><br><span class="line">│16│17│18│19│20│</span><br><span class="line">├──┼──┼──┼──┼──┤</span><br><span class="line">│21│22│23│24│25│</span><br><span class="line">└──┴──┴──┴──┴──┘</span><br><span class="line"></span><br><span class="line">第一个位置计算:</span><br><span class="line">1×1 + 2×0 + 3×(-1) + 6×2 + 7×0 + 8×(-2) + 11×1 + 12×0 + 13×(-1)</span><br><span class="line">= 1 + 0 - 3 + 12 + 0 - 16 + 11 + 0 - 13 = -8</span><br></pre></td></tr></table></figure><p>这个卷积核是一个<strong>垂直边缘检测器</strong> — 它能捕捉到图像中的垂直纹理。</p><h3 id="2-2-关键参数"><a href="#2-2-关键参数" class="headerlink" title="2.2 关键参数"></a>2.2 关键参数</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"></span><br><span class="line"><span class="comment"># 卷积层定义</span></span><br><span class="line">conv = nn.Conv2d(</span><br><span class="line">    in_channels=<span class="number">3</span>,     <span class="comment"># 输入通道数（RGB图片=3，灰度图=1）</span></span><br><span class="line">    out_channels=<span class="number">16</span>,   <span class="comment"># 输出通道数（用多少个卷积核）</span></span><br><span class="line">    kernel_size=<span class="number">3</span>,     <span class="comment"># 卷积核大小（3×3）</span></span><br><span class="line">    stride=<span class="number">1</span>,          <span class="comment"># 步长（每次移动几个像素）</span></span><br><span class="line">    padding=<span class="number">1</span>          <span class="comment"># 填充（保持尺寸不变）</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><strong>参数对输出的影响：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">输出尺寸 = (输入尺寸 + 2×padding - kernel_size) / stride + 1</span><br><span class="line"></span><br><span class="line">例：输入 32×32, kernel=3, padding=1, stride=1</span><br><span class="line">输出 = (32 + 2 - 3) / 1 + 1 = 32  # 尺寸不变</span><br><span class="line"></span><br><span class="line">例：输入 32×32, kernel=3, padding=0, stride=2</span><br><span class="line">输出 = (32 + 0 - 3) / 2 + 1 = 15.5 → 15  # 下采样</span><br></pre></td></tr></table></figure><h3 id="2-3-感受野（Receptive-Field）"><a href="#2-3-感受野（Receptive-Field）" class="headerlink" title="2.3 感受野（Receptive Field）"></a>2.3 感受野（Receptive Field）</h3><p>卷积网络中，越深的层能看到输入图像上越大的区域：</p><table><thead><tr><th align="center">层</th><th align="center">卷积核</th><th align="center">感受野</th></tr></thead><tbody><tr><td align="center">第1层卷积</td><td align="center">3×3</td><td align="center">3×3</td></tr><tr><td align="center">第2层卷积</td><td align="center">3×3</td><td align="center">5×5</td></tr><tr><td align="center">第3层卷积</td><td align="center">3×3</td><td align="center">7×7</td></tr></tbody></table><p><strong>两层 3×3 卷积 &#x3D; 一层 5×5 卷积</strong>，但参数量更少（2×9 vs 25）。所以现代 CNN 倾向用多层小卷积核堆叠。</p><hr><h2 id="三、池化层"><a href="#三、池化层" class="headerlink" title="三、池化层"></a>三、池化层</h2><p>池化层对特征图做<strong>下采样</strong>，减少参数量，增加平移不变性。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 最大池化：取窗口内最大值</span></span><br><span class="line">pool = nn.MaxPool2d(kernel_size=<span class="number">2</span>, stride=<span class="number">2</span>)</span><br><span class="line"><span class="comment"># 输出尺寸减半：32×32 → 16×16</span></span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">最大池化 (2×2, stride=2):</span><br><span class="line">┌──┬──┐    ┌──┐</span><br><span class="line">│1 │5 │    │5 │</span><br><span class="line">├──┼──┤ →  ├──┤</span><br><span class="line">│2 │8 │    │8 │</span><br><span class="line">└──┴──┘    └──┘</span><br></pre></td></tr></table></figure><p><strong>平均池化</strong>也常用，但在计算机视觉中最大池化更主流（保留最强的特征响应）。</p><hr><h2 id="四、经典-CNN-架构实战：CIFAR-10-分类"><a href="#四、经典-CNN-架构实战：CIFAR-10-分类" class="headerlink" title="四、经典 CNN 架构实战：CIFAR-10 分类"></a>四、经典 CNN 架构实战：CIFAR-10 分类</h2><p>我们来搭建一个类似 <strong>VGG 风格</strong>的 CNN——堆叠卷积层 + 池化层，最后接全连接分类。</p><h3 id="4-1-模型定义"><a href="#4-1-模型定义" class="headerlink" title="4.1 模型定义"></a>4.1 模型定义</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"><span class="keyword">import</span> torch.nn <span class="keyword">as</span> nn</span><br><span class="line"><span class="keyword">import</span> torch.nn.functional <span class="keyword">as</span> F</span><br><span class="line"><span class="keyword">import</span> torch.optim <span class="keyword">as</span> optim</span><br><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"><span class="keyword">from</span> torchvision <span class="keyword">import</span> datasets, transforms</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"></span><br><span class="line">device = torch.device(<span class="string">&#x27;cuda&#x27;</span> <span class="keyword">if</span> torch.cuda.is_available() <span class="keyword">else</span> <span class="string">&#x27;cpu&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;设备: <span class="subst">&#123;device&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SimpleCNN</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;简版 VGG 风格 CNN&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, num_classes=<span class="number">10</span></span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 特征提取器（卷积部分）</span></span><br><span class="line">        <span class="variable language_">self</span>.features = nn.Sequential(</span><br><span class="line">            <span class="comment"># Block 1: 32×32 → 32×32</span></span><br><span class="line">            nn.Conv2d(<span class="number">3</span>, <span class="number">32</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.Conv2d(<span class="number">32</span>, <span class="number">32</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.MaxPool2d(kernel_size=<span class="number">2</span>, stride=<span class="number">2</span>),  <span class="comment"># 32×32 → 16×16</span></span><br><span class="line"></span><br><span class="line">            <span class="comment"># Block 2: 16×16 → 8×8</span></span><br><span class="line">            nn.Conv2d(<span class="number">32</span>, <span class="number">64</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.Conv2d(<span class="number">64</span>, <span class="number">64</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.MaxPool2d(kernel_size=<span class="number">2</span>, stride=<span class="number">2</span>),  <span class="comment"># 16×16 → 8×8</span></span><br><span class="line"></span><br><span class="line">            <span class="comment"># Block 3: 8×8 → 4×4</span></span><br><span class="line">            nn.Conv2d(<span class="number">64</span>, <span class="number">128</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.Conv2d(<span class="number">128</span>, <span class="number">128</span>, kernel_size=<span class="number">3</span>, padding=<span class="number">1</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.MaxPool2d(kernel_size=<span class="number">2</span>, stride=<span class="number">2</span>),  <span class="comment"># 8×8 → 4×4</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 分类器（全连接部分）</span></span><br><span class="line">        <span class="variable language_">self</span>.classifier = nn.Sequential(</span><br><span class="line">            nn.Dropout(<span class="number">0.5</span>),</span><br><span class="line">            nn.Linear(<span class="number">128</span> * <span class="number">4</span> * <span class="number">4</span>, <span class="number">256</span>),</span><br><span class="line">            nn.ReLU(inplace=<span class="literal">True</span>),</span><br><span class="line">            nn.Dropout(<span class="number">0.5</span>),</span><br><span class="line">            nn.Linear(<span class="number">256</span>, num_classes),</span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        x = <span class="variable language_">self</span>.features(x)</span><br><span class="line">        x = x.view(x.size(<span class="number">0</span>), -<span class="number">1</span>)  <span class="comment"># 展平</span></span><br><span class="line">        x = <span class="variable language_">self</span>.classifier(x)</span><br><span class="line">        <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">model = SimpleCNN().to(device)</span><br><span class="line"><span class="built_in">print</span>(model)</span><br></pre></td></tr></table></figure><p><strong>参数量对比：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SimpleCNN: 约 85 万参数</span><br><span class="line">等效全连接网络: 图片 32×32×3=3072，一层 256 个神经元 → 78 万参数</span><br><span class="line">但 CNN 有 6 层卷积，同样深度的全连接网络参数量会爆炸</span><br></pre></td></tr></table></figure><h3 id="4-2-数据加载（CIFAR-10）"><a href="#4-2-数据加载（CIFAR-10）" class="headerlink" title="4.2 数据加载（CIFAR-10）"></a>4.2 数据加载（CIFAR-10）</h3><p>CIFAR-10 是 32×32 的彩色图片（10 个类别：飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车）。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 数据增强（提高泛化能力）</span></span><br><span class="line">train_transform = transforms.Compose([</span><br><span class="line">    transforms.RandomHorizontalFlip(),   <span class="comment"># 随机水平翻转</span></span><br><span class="line">    transforms.RandomCrop(<span class="number">32</span>, padding=<span class="number">4</span>),<span class="comment"># 随机裁剪</span></span><br><span class="line">    transforms.ColorJitter(<span class="number">0.1</span>, <span class="number">0.1</span>),   <span class="comment"># 颜色抖动</span></span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(</span><br><span class="line">        (<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>),       <span class="comment"># CIFAR-10 的 RGB 均值</span></span><br><span class="line">        (<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>)        <span class="comment"># CIFAR-10 的 RGB 标准差</span></span><br><span class="line">    )</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">test_transform = transforms.Compose([</span><br><span class="line">    transforms.ToTensor(),</span><br><span class="line">    transforms.Normalize(</span><br><span class="line">        (<span class="number">0.4914</span>, <span class="number">0.4822</span>, <span class="number">0.4465</span>),</span><br><span class="line">        (<span class="number">0.2470</span>, <span class="number">0.2435</span>, <span class="number">0.2616</span>)</span><br><span class="line">    )</span><br><span class="line">])</span><br><span class="line"></span><br><span class="line">train_dataset = datasets.CIFAR10(</span><br><span class="line">    root=<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">True</span>, download=<span class="literal">True</span>, transform=train_transform</span><br><span class="line">)</span><br><span class="line">test_dataset = datasets.CIFAR10(</span><br><span class="line">    root=<span class="string">&#x27;./data&#x27;</span>, train=<span class="literal">False</span>, download=<span class="literal">True</span>, transform=test_transform</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">train_loader = DataLoader(train_dataset, batch_size=<span class="number">128</span>, shuffle=<span class="literal">True</span>, num_workers=<span class="number">2</span>)</span><br><span class="line">test_loader = DataLoader(test_dataset, batch_size=<span class="number">128</span>, shuffle=<span class="literal">False</span>, num_workers=<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;训练集: <span class="subst">&#123;<span class="built_in">len</span>(train_dataset)&#125;</span> 张&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;测试集: <span class="subst">&#123;<span class="built_in">len</span>(test_dataset)&#125;</span> 张&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;类别: <span class="subst">&#123;train_dataset.classes&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><h3 id="4-3-训练"><a href="#4-3-训练" class="headerlink" title="4.3 训练"></a>4.3 训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">criterion = nn.CrossEntropyLoss()</span><br><span class="line">optimizer = optim.Adam(model.parameters(), lr=<span class="number">0.001</span>)</span><br><span class="line">scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=<span class="number">30</span>)</span><br><span class="line"></span><br><span class="line">EPOCHS = <span class="number">30</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(EPOCHS):</span><br><span class="line">    model.train()</span><br><span class="line">    running_loss = <span class="number">0.0</span></span><br><span class="line">    correct = <span class="number">0</span></span><br><span class="line">    total = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> data, target <span class="keyword">in</span> train_loader:</span><br><span class="line">        data, target = data.to(device), target.to(device)</span><br><span class="line"></span><br><span class="line">        optimizer.zero_grad()</span><br><span class="line">        output = model(data)</span><br><span class="line">        loss = criterion(output, target)</span><br><span class="line">        loss.backward()</span><br><span class="line">        optimizer.step()</span><br><span class="line"></span><br><span class="line">        running_loss += loss.item()</span><br><span class="line">        _, preds = output.<span class="built_in">max</span>(<span class="number">1</span>)</span><br><span class="line">        total += target.size(<span class="number">0</span>)</span><br><span class="line">        correct += preds.eq(target).<span class="built_in">sum</span>().item()</span><br><span class="line"></span><br><span class="line">    scheduler.step()</span><br><span class="line"></span><br><span class="line">    train_acc = <span class="number">100.</span> * correct / total</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;Epoch <span class="subst">&#123;epoch+<span class="number">1</span>:2d&#125;</span>/<span class="subst">&#123;EPOCHS&#125;</span> | Loss: <span class="subst">&#123;running_loss/<span class="built_in">len</span>(train_loader):<span class="number">.4</span>f&#125;</span> | &#x27;</span></span><br><span class="line">          <span class="string">f&#x27;Train Acc: <span class="subst">&#123;train_acc:<span class="number">.2</span>f&#125;</span>%&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 每个 epoch 评估测试集</span></span><br><span class="line">    model.<span class="built_in">eval</span>()</span><br><span class="line">    test_correct = <span class="number">0</span></span><br><span class="line">    test_total = <span class="number">0</span></span><br><span class="line">    <span class="keyword">with</span> torch.no_grad():</span><br><span class="line">        <span class="keyword">for</span> data, target <span class="keyword">in</span> test_loader:</span><br><span class="line">            data, target = data.to(device), target.to(device)</span><br><span class="line">            _, preds = model(data).<span class="built_in">max</span>(<span class="number">1</span>)</span><br><span class="line">            test_total += target.size(<span class="number">0</span>)</span><br><span class="line">            test_correct += preds.eq(target).<span class="built_in">sum</span>().item()</span><br><span class="line">    test_acc = <span class="number">100.</span> * test_correct / test_total</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;            Test  Acc: <span class="subst">&#123;test_acc:<span class="number">.2</span>f&#125;</span>%&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;训练完成 ✅&quot;</span>)</span><br></pre></td></tr></table></figure><p>用 GPU 训练 30 个 epoch 大约 5-10 分钟，最终测试准确率应达到 <strong>80-85%</strong>（对于这个简单的网络来说已经不错了）。</p><h3 id="4-4-可视化卷积核"><a href="#4-4-可视化卷积核" class="headerlink" title="4.4 可视化卷积核"></a>4.4 可视化卷积核</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看第一层卷积核</span></span><br><span class="line">first_conv = model.features[<span class="number">0</span>]</span><br><span class="line">weights = first_conv.weight.data.cpu()</span><br><span class="line"></span><br><span class="line">fig, axes = plt.subplots(<span class="number">4</span>, <span class="number">8</span>, figsize=(<span class="number">12</span>, <span class="number">6</span>))</span><br><span class="line"><span class="keyword">for</span> i, ax <span class="keyword">in</span> <span class="built_in">enumerate</span>(axes.flat):</span><br><span class="line">    <span class="keyword">if</span> i &lt; weights.size(<span class="number">0</span>):</span><br><span class="line">        <span class="comment"># 每个卷积核有 3 个通道（RGB），取平均值可视化</span></span><br><span class="line">        kernel = weights[i].mean(dim=<span class="number">0</span>)</span><br><span class="line">        ax.imshow(kernel, cmap=<span class="string">&#x27;viridis&#x27;</span>)</span><br><span class="line">        ax.axis(<span class="string">&#x27;off&#x27;</span>)</span><br><span class="line">plt.suptitle(<span class="string">&#x27;第一层 32 个卷积核可视化&#x27;</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure><p>你会看到：有的卷积核学会检测边缘（黑白条纹），有的学会检测颜色块，有的是纹理模式——这就是 CNN 的”神经元”。</p><hr><h2 id="五、CNN-设计原则"><a href="#五、CNN-设计原则" class="headerlink" title="五、CNN 设计原则"></a>五、CNN 设计原则</h2><h3 id="5-1-经典设计模式"><a href="#5-1-经典设计模式" class="headerlink" title="5.1 经典设计模式"></a>5.1 经典设计模式</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入 → [Conv → ReLU]×N → Pool → [Conv → ReLU]×M → Pool → ... → FC → FC → Softmax</span><br><span class="line">                              ↓                                ↓</span><br><span class="line">                         逐步加深通道                      逐步减少神经元</span><br><span class="line">                         逐步缩小尺寸</span><br></pre></td></tr></table></figure><table><thead><tr><th>层类型</th><th>通道数变化</th><th>尺寸变化</th></tr></thead><tbody><tr><td>浅层卷积</td><td>3 → 32 → 64</td><td>32×32 → 16×16</td></tr><tr><td>中层卷积</td><td>64 → 128 → 256</td><td>16×16 → 8×8</td></tr><tr><td>深层卷积</td><td>256 → 512</td><td>8×8 → 4×4</td></tr><tr><td>全连接</td><td>512×4×4 → 256 → 10</td><td>展平</td></tr></tbody></table><h3 id="5-2-经典-CNN-演进"><a href="#5-2-经典-CNN-演进" class="headerlink" title="5.2 经典 CNN 演进"></a>5.2 经典 CNN 演进</h3><table><thead><tr><th align="center">模型</th><th align="center">年份</th><th>特点</th><th align="center">参数量</th></tr></thead><tbody><tr><td align="center">LeNet-5</td><td align="center">1998</td><td>第一个 CNN，手写数字识别</td><td align="center">6 万</td></tr><tr><td align="center">AlexNet</td><td align="center">2012</td><td>ImageNet 冠军，深度学习元年</td><td align="center">6000 万</td></tr><tr><td align="center">VGG-16</td><td align="center">2014</td><td>堆叠 3×3 小卷积核，简洁优雅</td><td align="center">1.38 亿</td></tr><tr><td align="center">ResNet-50</td><td align="center">2015</td><td>残差连接，解决了深层网络梯度消失</td><td align="center">2500 万</td></tr><tr><td align="center">EfficientNet</td><td align="center">2019</td><td>神经架构搜索，效率最高</td><td align="center">400 万-3000 万</td></tr></tbody></table><p><strong>ResNet 的残差连接</strong>是近年来最重要的创新之一：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ResidualBlock</span>(nn.Module):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;残差块&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, channels</span>):</span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="variable language_">self</span>.conv1 = nn.Conv2d(channels, channels, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.bn1 = nn.BatchNorm2d(channels)</span><br><span class="line">        <span class="variable language_">self</span>.conv2 = nn.Conv2d(channels, channels, <span class="number">3</span>, padding=<span class="number">1</span>)</span><br><span class="line">        <span class="variable language_">self</span>.bn2 = nn.BatchNorm2d(channels)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        residual = x</span><br><span class="line">        out = F.relu(<span class="variable language_">self</span>.bn1(<span class="variable language_">self</span>.conv1(x)))</span><br><span class="line">        out = <span class="variable language_">self</span>.bn2(<span class="variable language_">self</span>.conv2(out))</span><br><span class="line">        out += residual  <span class="comment"># 残差连接：跳过两层，直接加上输入</span></span><br><span class="line">        <span class="keyword">return</span> F.relu(out)</span><br></pre></td></tr></table></figure><p>残差连接让梯度可以直接通过跳跃连接反向传播，解决了层数太深梯度消失的问题——这也是现在所有大模型（包括 Transformer）都在用残差连接的原因。</p><hr><h2 id="六、三张图看懂-CNN-流程"><a href="#六、三张图看懂-CNN-流程" class="headerlink" title="六、三张图看懂 CNN 流程"></a>六、三张图看懂 CNN 流程</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">输入图片 (3×32×32)</span><br><span class="line">    │</span><br><span class="line">    ▼</span><br><span class="line">┌─────────────────────────────────────────────────────┐</span><br><span class="line">│                 特征提取器（卷积部分）                  │</span><br><span class="line">├─────────────────────────────────────────────────────┤</span><br><span class="line">│  Conv 3×32×32 → 32×32×32  (32个卷积核，提取边缘纹理) │</span><br><span class="line">│  Conv 32×32×32 → 32×32×32  (第二层，提取简单形状)    │</span><br><span class="line">│  Pool 32×32×32 → 32×16×16  (下采样，保留最强特征)    │</span><br><span class="line">│  Conv 32×16×16 → 64×16×16  (更深，提取图案模式)     │</span><br><span class="line">│  Conv 64×16×16 → 64×16×16                          │</span><br><span class="line">│  Pool 64×16×16 → 64×8×8                            │</span><br><span class="line">│  Conv 64×8×8 → 128×8×8   (最深，提取语义概念)      │</span><br><span class="line">│  Conv 128×8×8 → 128×8×8                            │</span><br><span class="line">│  Pool 128×8×8 → 128×4×4                            │</span><br><span class="line">└──────────────────────┬──────────────────────────────┘</span><br><span class="line">                       │ 展平: 128×4×4 = 2048</span><br><span class="line">                       ▼</span><br><span class="line">┌─────────────────────────────────────────────────────┐</span><br><span class="line">│                 分类器（全连接部分）                    │</span><br><span class="line">├─────────────────────────────────────────────────────┤</span><br><span class="line">│            FC 2048 → 256   (特征 → 类别置信度)       │</span><br><span class="line">│            FC 256 → 10                              │</span><br><span class="line">└──────────────────────┬──────────────────────────────┘</span><br><span class="line">                       │</span><br><span class="line">                       ▼</span><br><span class="line">                    [0.01, 0.02, 0.92, ...]  ← 输出概率</span><br></pre></td></tr></table></figure><hr><h2 id="七、总结"><a href="#七、总结" class="headerlink" title="七、总结"></a>七、总结</h2><p>本文你掌握了：</p><table><thead><tr><th>知识点</th><th align="center">掌握</th></tr></thead><tbody><tr><td>CNN 为什么比全连接更适合图片</td><td align="center">✅</td></tr><tr><td>卷积操作原理（卷积核、步长、填充）</td><td align="center">✅</td></tr><tr><td>池化层的作用</td><td align="center">✅</td></tr><tr><td>感受野与多层小卷积核</td><td align="center">✅</td></tr><tr><td>用 PyTorch 搭建 CNN 完成 CIFAR-10 分类</td><td align="center">✅ <strong>实战</strong></td></tr><tr><td>经典 CNN 架构演进（VGG&#x2F;ResNet）</td><td align="center">✅</td></tr><tr><td>残差连接原理</td><td align="center">✅</td></tr></tbody></table><p><strong>下一步推荐：</strong></p><ul><li><a href="/2026/07/03/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%85%A5%E9%97%A8%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%9F%BA%E7%A1%80/">计算机视觉入门：图像处理基础</a>（即将发布）</li><li><a href="/2026/07/03/%E5%AE%9E%E6%88%98%EF%BC%9A%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BBCIFAR-10/">实战：图像分类（CIFAR-10）</a>（即将发布）</li><li><a href="/2026/07/03/PyTorch%E5%AE%9E%E6%88%98%EF%BC%88%E4%B8%80%EF%BC%89%EF%BC%9A%E5%BC%A0%E9%87%8F%E6%93%8D%E4%BD%9C%E4%B8%8E%E8%87%AA%E5%8A%A8%E5%BE%AE%E5%88%86/">PyTorch 实战（一）：张量操作与自动微分</a></li></ul>]]>
    </content>
    <id>https://aijvs.com/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/</id>
    <link href="https://aijvs.com/2026/07/03/%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84%E8%AF%A6%E8%A7%A3%EF%BC%9ACNN%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
    <published>2026-07-03T06:00:00.000Z</published>
    <summary>CNN 卷积神经网络完整教程：卷积层、池化层、感受野的原理与 PyTorch 实现，附 CIFAR-10 分类实战。</summary>
    <title>神经网络架构详解：CNN 卷积神经网络</title>
    <updated>2026-07-03T06:00:00.000Z</updated>
  </entry>
</feed>
