<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Posts on Ganko Space</title><link>https://ganko.asia/posts/</link><description>Recent content in Posts on Ganko Space</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 28 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://ganko.asia/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>SAM 3D:3Dfy anything in Images</title><link>https://ganko.asia/posts/cvpr26_sam3d/</link><pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cvpr26_sam3d/</guid><description>&lt;blockquote>
&lt;p>原本看这篇论文以为是一个比之前更接近真实世界的3d生成新任务，还想着水他一篇，但是看了之后发现数据集不公开，做的话也没那么多资源，但是meta的工作，所以主要从这里边学习大厂大规模研究的工程和技术细节:数据pipline怎么做，训练策略以及实验评测设计。&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>这是看完之后的Ganko，纯大厂风格的力大砖飞工作，鉴定完毕，又浪费一天，tmd。（没有看不起的意思，我觉得我的小作坊编故事风格的工作还不如这种，这种至少有用）&lt;/p>&lt;/blockquote>
&lt;h2 id="论文想解决的问题">论文想解决的问题&lt;/h2>
&lt;p>这篇论文要解决的是三个层层递进的问题，一个是旧3d重建任务针对单个物体，但是真实世界中的物体通常有遮挡，远距离等各种影响。这篇论文要解决的是一整个真实场景的3d重建，在重建场景中每个物体的同时预测物体的具体位姿以重建整个场景。因此就会引出第二个问题，3d模型数据不像自然2d图像和语言数据，自然界存在很多，合成数据有sim2real的问题要解决。然后就是标注问题，分类任务普通人就能标注，极低成本获得大量数据，但是3d建模需要专业技术。&lt;/p>
&lt;h2 id="解决思路">解决思路&lt;/h2>
&lt;p>三个问题是递进的，解决了标注和数据问题，设计迭代模型反而简单。所以先从标注成本入手，普通人不能进行3d建模，但是能区分3d建模质量的高低（Human in loop - HIL），设计了MITL pipline，让普通人从几个候选中挑选并且对齐位姿（怎么获得候选个问题，就是冷启动问题，核心方法会写）。用这个pipline收集大规模的数据，然后针对真实世界的复杂性设计了方法和仿LLM的训练策略，（合成预训练-半合成中期训练-真实数据后训练）。&lt;/p>
&lt;h2 id="核心方法">核心方法&lt;/h2>
&lt;h3 id="网络结构">网络结构&lt;/h3>
&lt;p>&lt;img src="https://ganko.asia/images/CVPR26_SAM3D/image.png" alt="alt text">&lt;/p>
&lt;p>每个部分的具体实现：&lt;/p>
&lt;ul>
&lt;li>Encoder：Encoder全都使用DINOv2，得到4组条件token，一组是裁剪物体：通过掩码M以及对应的裁剪二值Mask对裁剪的图像I进行编码，提供聚焦的高分辨率的物体视图。另一组是全图I以及全图二值掩码，提供全局上下文线索。点云Encoder可选可不选，可以选用硬件采集也可以用其他深度估计方法来得到。&lt;/li>
&lt;li>Geometry Model：论文的问题定义中把这个任务定义成了一个条件分布估计 $q(S, T, R, t, s|I, M )$，在具体的实现中又把整个任务拆成了两个条件分布，几何模型负责 $p(O,R,t,s∣I,M)$,回答物体在什么地方，大概长什么样子。（O是粗形状，R是6d pose，t是物体在相机系中的3维位置，s是在三个轴上的缩放）。输入图像和掩码经过编码后，送入一个 12 亿参数的流匹配 Transformer（flow transformer），采用 Mixture-of-Transformers (MoT) 架构——一种多模态 Transformer 变体，通过精心设计的 attention mask（Fig. 2 右图所示）让不同模态（图像、掩码、形状、位姿）之间既共享信息又保持各自的处理流（two-stream approach）。MoT 的特点是稀疏高效：不同模态有各自的 Transformer 层，只在多模态自注意力层做信息交互。&lt;strong>（本质双流加交叉注意力）&lt;/strong>&lt;/li>
&lt;li>Texture &amp;amp; Refinement Model：这部分负责 $p(S,T∣I,M,O)$,从粗形状 O 中只保留&amp;quot;被占据&amp;quot;的体素（active voxels），跳过空区域，一个 6 亿参数的稀疏潜流 Transformer（sparse latent flow transformer）在这些活跃体素上做两件事——把粗糙的几何细节补全（比如把 643643 的粗体素细化成更高分辨率的形状 S），同时合成物体的纹理 T。&lt;/li>
&lt;li>3D Decoders：得到Texture &amp;amp; Refinement Model的隐空间的特征表示之后，使用两个独立的解码器解码，一个mesh解码器用于传统建模行业，另一个Gaussian解码器用于实时渲染和新视角合成，两个解码器共享一个隐编码空间。&lt;/li>
&lt;/ul>
&lt;h3 id="训练">训练&lt;/h3>
&lt;p>&lt;img src="https://ganko.asia/images/CVPR26_SAM3D/image-1.png" alt="alt text">&lt;/p></description></item><item><title>TODO</title><link>https://ganko.asia/posts/%E9%95%BF%E6%9C%9F%E5%AD%A6%E4%B9%A0todo/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E9%95%BF%E6%9C%9F%E5%AD%A6%E4%B9%A0todo/</guid><description>&lt;blockquote>
&lt;p>一个索引+TODO&lt;/p>&lt;/blockquote>
&lt;ul>
&lt;li>&lt;a href="https://ganko.asia/posts/cs336-%E5%86%99%E5%9C%A8%E6%89%80%E6%9C%89%E4%B9%8B%E5%89%8D/">CS336 笔记&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/nanogpt/">NanoGPT：从零训练一个 LLM&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/nanovlm-llava/">NanoVLM-LLaVA&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/nanovlm-anyres/">NanoVLM-AnyRes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/codebymyself-transformer/">CodeByMySelf-Transformer&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/codebymyself-diffusion/">CodeByMySelf-Diffusion&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/pytorch-tricks/">Pytorch-Tricks&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="todo">TODO&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://ganko.asia/posts/codebymyself-vae/">CodeByMySelf-VAE&lt;/a>（TODO）&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/codebymyself-rl/">CodeByMySelf-RL&lt;/a>（TODO）&lt;/li>
&lt;li>&lt;a href="https://ganko.asia/posts/%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E5%AE%9E%E8%B7%B5/">并行训练实践&lt;/a>（未完成）&lt;/li>
&lt;/ul></description></item><item><title>关于爱情的一些思考</title><link>https://ganko.asia/posts/%E5%85%B3%E4%BA%8E%E7%88%B1%E6%83%85%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/</link><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E5%85%B3%E4%BA%8E%E7%88%B1%E6%83%85%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/</guid><description>&lt;h2 id="什么是回避型依恋">什么是回避型依恋&lt;/h2>
&lt;p>回避型依恋的核心特征：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>恐惧亲密&lt;/strong>——不是不需要，是怕被伤害&lt;/li>
&lt;li>&lt;strong>推开即测试&lt;/strong>——冷落你不是不爱你，是在看你走不走&lt;/li>
&lt;li>&lt;strong>自我消化情绪&lt;/strong>——有事自己扛，不习惯求助&lt;/li>
&lt;li>&lt;strong>忽冷忽热&lt;/strong>——靠近了怕失去自我，远了又怕失去你&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="最核心的一件事用她感受爱的方式去爱她">最核心的一件事：用她感受爱的方式去爱她&lt;/h2>
&lt;p>这不是一条技巧，是下面所有技巧背后的那句话：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>爱一个人，要用她感受爱的方式去爱她，而不是用我自己能感受爱的方式去爱。&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>我们默认用自己的方式去爱：我收到礼物会感动，所以送你礼物；我说「我爱你」会被安慰，所以反复说；我需要陪伴，所以以为多陪你就是爱你。但这其实是在&lt;strong>爱自己&lt;/strong>——在用「如果我被这样对待，我会感到被爱」来推测她。她接收爱的方式可能完全不同：&lt;/p>
&lt;ul>
&lt;li>她可能不看你说了什么，只看你有没有在&lt;/li>
&lt;li>她可能不要惊喜，要的是稳定、是说话算数&lt;/li>
&lt;li>你花了一整天准备的浪漫，她的需求可能只是你按时回她消息&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>检验的标准不是「我表达了没有」，而是「她收到了没有」。&lt;/strong> 以她的感受为准，不以你的付出为准。&lt;/p>
&lt;p>怎么知道她怎么感受爱：&lt;/p>
&lt;ul>
&lt;li>看她怎么对人好——人通常给出自己最想收到的那种爱&lt;/li>
&lt;li>看她抱怨什么——抱怨里藏着需求：「你总是不记得小事」→ 细节是她爱的语言&lt;/li>
&lt;li>直接问：「怎样会让你觉得被爱？」——这个问题本身，就是一种爱的表达&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>这个原则对所有关系都成立，不只是回避型。&lt;/strong> 只是对回避型尤其致命：她接收爱的方式和你表达爱的方式，差异往往最大。你用热烈的爱去追一个需要安静的爱的人——她收不到，你觉得委屈；你觉得付出很多，她觉得窒息。两个人都受伤。&lt;/p>
&lt;p>下面所有的应对原则，都是这句话的具体化。&lt;/p>
&lt;hr>
&lt;h2 id="应对原则">应对原则&lt;/h2>
&lt;h3 id="1-不追但在">1. 不追，但在&lt;/h3>
&lt;p>追太紧她会跑，退太远她会觉得「果然如此」。
最好的距离：&lt;strong>让她看见你一直在，但不逼她过来。&lt;/strong>&lt;/p>
&lt;h3 id="2-用行动不用承诺">2. 用行动，不用承诺&lt;/h3>
&lt;p>回避型不相信「永远」「以后」这种词。
她信你做了的事：你等了她、你记得她说过的话、你在她冷的时候没走。&lt;/p>
&lt;h3 id="3-吵架时语气--内容">3. 吵架时语气 &amp;gt; 内容&lt;/h3>
&lt;p>你赢了逻辑，她输了安全感。一旦安全感没了，她会缩回去很久。&lt;/p>
&lt;h3 id="4-别问她你怎么了">4. 别问她「你怎么了」&lt;/h3>
&lt;p>她想说的时候会说。问就是压力。换成「我在，你什么时候想说都行。」&lt;/p>
&lt;h3 id="5-接受撤退不是拒绝">5. 接受撤退不是拒绝&lt;/h3>
&lt;p>她冷淡 = 系统过载，自动关机。不是讨厌你。给她时间重启。&lt;/p>
&lt;h3 id="6-表达情绪时收着点">6. 表达情绪时收着点&lt;/h3>
&lt;p>回避型对强烈情绪过敏。平静的、稳定的表达，比激烈的告白更让她安心。&lt;/p>
&lt;h3 id="7-她逃之前你先退半步">7. 她逃之前，你先退半步&lt;/h3>
&lt;p>当她开始退缩，不要等她冷到零度再反应。在她缩的初期，主动拉开一点距离——但不是冷漠，是&lt;strong>控制节奏&lt;/strong>。&lt;/p>
&lt;p>话术示例：「最近有点忙，周末再找你。」&lt;/p>
&lt;ul>
&lt;li>「忙」→ 不是她的错，不是她在被惩罚&lt;/li>
&lt;li>「周末」→ 给了时间锚点，她知道你不是消失&lt;/li>
&lt;li>你主动走半步 → 她不用愧疚地逃&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>分析：&lt;/strong> 回避型的退缩本质上是对「被吞没」的恐惧——她感觉关系在升温，本能想拉开距离保护自我边界。如果你等她先冷，她会觉得自己伤害了你，然后更不敢回来。如果你在她感受到压力之前主动松一松，她不需要逃，因为绳子没勒紧。&lt;/p>
&lt;p>&lt;strong>建议：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在她态度开始变淡的第一天就主动减频，不要在第三天崩溃追问&lt;/li>
&lt;li>减频时带一个「客观理由」（课题、开会、赶 due），让她不用猜&lt;/li>
&lt;li>约定的回头时间一定要兑现——这是建立信任的关键测试&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="关键信号">关键信号&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>信号&lt;/th>
&lt;th>含义&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>主动联系你&lt;/td>
&lt;td>对你信任度很高&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>跟你说脆弱的事&lt;/td>
&lt;td>已经把你放进内圈&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>之后突然冷淡&lt;/td>
&lt;td>&lt;strong>不是后悔，是后怕&lt;/strong>——这是最关键的判断节点&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>在你面前任性&lt;/td>
&lt;td>安全感足够高，开始摘面具&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;hr>
&lt;h2 id="给自己的提醒">给自己的提醒&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>不能把全部安全感寄托在她身上。&lt;/strong>&lt;/p></description></item><item><title>[论文阅读] Vision Transformers Need More Than Registers</title><link>https://ganko.asia/posts/read_vit_lazy_aggregation/</link><pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/read_vit_lazy_aggregation/</guid><description>&lt;h2 id="一句话总结">一句话总结&lt;/h2>
&lt;p>ViT使用语义无关的背景块作为表示全局语义的捷径，在全局注意力和粗粒度语义监督的驱动下。这篇论文选择性地将补丁特征集成到CLS token中，减少了背景主导的快捷方式的影响，并在标签、文本和自监督的情况下，在12个基准测试中提高性能。&lt;/p>
&lt;h2 id="论文信息">论文信息&lt;/h2>
&lt;ul>
&lt;li>标题：Vision Transformers Need More Than Registers&lt;/li>
&lt;li>作者：Cheng Shi, Yizhou Yu, Sibei Yang (University of Hong Kong &amp;amp; Sun Yat-sen University)&lt;/li>
&lt;li>会议/期刊：arXiv preprint (2602.22394)&lt;/li>
&lt;li>链接：&lt;a href="https://arxiv.org/abs/2602.22394">https://arxiv.org/abs/2602.22394&lt;/a>&lt;/li>
&lt;li>代码：&lt;a href="https://github.com/ChengShiest/LAST-ViT">https://github.com/ChengShiest/LAST-ViT&lt;/a>&lt;/li>
&lt;li>前置工作：&lt;em>Vision Transformers Need Registers&lt;/em> (Darcet et al., ICLR 2024)&lt;/li>
&lt;/ul>
&lt;h2 id="研究背景与动机">研究背景与动机&lt;/h2>
&lt;ul>
&lt;li>原始 ViT 中的 CLS token 用于聚合全局图像表示&lt;/li>
&lt;li>Darcet et al. (ICLR 2024) 发现 ViT 的特征图中会出现异常的 high-norm artifact patches，提出添加额外的 register tokens 来吸收这些 artifacts&lt;/li>
&lt;li>但这篇论文认为问题不仅仅是 artifact patches —— ViT 存在更根本的 &lt;strong>lazy aggregation&lt;/strong> 行为，Lazy Aggregation：在图像级粗粒度监督下，ViT倾向于将前景语义&amp;quot;扩散&amp;quot;到大量背景patch中，利用背景token作为编码全局语义的捷径。&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>lazy aggregation是这篇论文贡献中提出的一个关键假设，但是我不认为应该这么局限于vit，我认为这是对于目前整个学习范式的问题，数据不可能做到面面俱到，模型在寻找最优解的时候可能会偏向于利用背景分析，比如dataset中所有bird类图片的background都是类似的，模型就会把背景作为一个主要判断依据，但是从另一个角度来看，又不能完全不考虑背景信息，例如一个像狗又像狼的生物，在野外会判断成狼，但是在农村院子里就是狗，虽然通过主体自身信息能做到百分之八十到九十的准确性，但是背景并非完全无用，就像我在我的论文中描述的一样。&lt;/p></description></item><item><title>CS336 Lecture 5-6: GPUs &amp; Kernels, Triton</title><link>https://ganko.asia/posts/cs336-lecture5-6-gpus-kernels-triton/</link><pubDate>Mon, 08 Jun 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-lecture5-6-gpus-kernels-triton/</guid><description>&lt;h2 id="为什么这两讲至关重要">为什么这两讲至关重要&lt;/h2>
&lt;p>在已经学过的课程中，L1-L4 讲的是&amp;quot;模型长什么样&amp;quot;，L7-L8 讲的是&amp;quot;多卡怎么协作&amp;quot;。&lt;strong>L5-L6 卡在两者之间——单卡内部到底在发生什么。&lt;/strong>&lt;/p>
&lt;p>如果你不理解 GPU 的硬件结构，你就无法理解：&lt;/p>
&lt;ul>
&lt;li>为什么 Flash Attention 是过去五年 LLM 领域最重要的系统优化&lt;/li>
&lt;li>为什么大矩阵乘法是&amp;quot;compute-bound&amp;quot;而 Attention 是&amp;quot;memory-bound&amp;quot;&lt;/li>
&lt;li>为什么你写的 PyTorch 代码有时 GPU 利用率只有 30%&lt;/li>
&lt;li>ZeRO-3 的通信开销到底卡在哪里（看懂 L7-8 那块没懂的）&lt;/li>
&lt;/ul>
&lt;p>Percy 在 L6 的原话很直白：&lt;strong>&amp;ldquo;You cannot optimize what you don&amp;rsquo;t measure, and you cannot measure what you don&amp;rsquo;t understand.&amp;rdquo;&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="lecture-5gpu-架构解剖tatsu">Lecture 5：GPU 架构解剖（Tatsu）&lt;/h2>
&lt;h3 id="51-从一张-h100-说起">5.1 从一张 H100 说起&lt;/h3>
&lt;p>H100 的基本参数：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>HBM（显存）&lt;/strong>：80GB，带宽 ~3.35 TB/s&lt;/li>
&lt;li>&lt;strong>SRAM（片上共享内存）&lt;/strong>：每 SM 约 256KB，总带宽 ~几十 TB/s（比 HBM 快一个数量级）&lt;/li>
&lt;li>&lt;strong>计算能力&lt;/strong>：BF16 下 ~990 TFLOPS&lt;/li>
&lt;/ul>
&lt;p>关键不在于这些数字有多大，而在于&lt;strong>数字之间的比例&lt;/strong>。&lt;/p></description></item><item><title>CV领域的多任务统一模型</title><link>https://ganko.asia/posts/cv%E9%A2%86%E5%9F%9F%E7%9A%84%E5%A4%9A%E4%BB%BB%E5%8A%A1%E7%BB%9F%E4%B8%80%E6%A8%A1%E5%9E%8B/</link><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cv%E9%A2%86%E5%9F%9F%E7%9A%84%E5%A4%9A%E4%BB%BB%E5%8A%A1%E7%BB%9F%E4%B8%80%E6%A8%A1%E5%9E%8B/</guid><description>&lt;blockquote>
&lt;p>改论文intro的时候突然想到，看到过有人问为什么CV领域没一个Scaling law，很明显的原因是CV领域不同的任务太多了，先不说图片的信息密度问题，单是把所有任务统一到一个模型里，都很费时间。但是又想到，大部分cv任务本质上可以通过完美的理解图片来解决，比如：模型知道每一块每一个像素具体是哪个类别的（或者有一些任务是某种属性）。这样就有一个想法: 假设有一个模型，在给定一个框（可以是像素，也可以是规则/不规则的块）和完整图片，模型需要知道这个框是什么类别的，这样的话分类任务可以通过最高占比来决定（一张蜜蜂的图片，大部分是空白蓝天会分类错误，但是这并不能证明这个方法的缺陷，只能说明预先定义了空白蓝天是无意义的类别（从平常摄影的角度来说，也可能是对焦问题））；分割和定位任务可以通过对每一个像素点（或者说大patch，像素太小了）循环问是什么类别来得到，不过这个时候就会有一个问题，效率问题，很自然就想到一个办法，采样。 想到这里突然就联系起来了 ，SAM用的就是用的采样，但是依然很慢其实（）。想法就到这里了，虽然没什么结果，但是让我知道了这个领域，这篇就用来记一下试图去统一CV任务的论文阅读了（可能论文本身没写，但是确是有这种趋势或者可能的也会在这里放） 2026/6/5&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;blockquote>
&lt;p>写完上边那些突然想到，超分、去雾、生成这些任务怎么统一啊，诶，看来还是论文看少了。最后感慨一下，如果放在以前，脑子里有这么一个奇怪的idea，我需要花费数周的时间查询阅读相关论文，但是现在只需要一个小时就能大概了解这个方向大家在做什么。 2026/6/5&lt;/p>&lt;/blockquote>
&lt;h2 id="gpt4roieccv-workshops-2024">GPT4RoI[ECCV WORKSHOPS 2024]&lt;/h2>
&lt;p>GPT最推荐我读的论文。它用户 instruction 里的 RoI / box 替换成 RoI features，再送进 LLM，做 region-level image understanding。它还强调 region-text pairs 对细粒度理解的重要性。&lt;/p></description></item><item><title>NanoVLM-AnyRes</title><link>https://ganko.asia/posts/nanovlm-anyres/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/nanovlm-anyres/</guid><description>&lt;blockquote>
&lt;p>AnyRes（动态高分辨率）是 LLaVA-NeXT 1.6 的核心创新，解决了固定分辨率下细节丢失的问题：将图像按纵横比自适应切分为多个 tile，每个 tile 独立编码后和全局缩略图一起送入 LLM。NanoVLM 在保留原始单图模式的基础上新增了 AnyRes 能力，两个模式通过一个布尔值切换。&lt;/p>&lt;/blockquote>
&lt;h2 id="问题固定分辨率的瓶颈">问题：固定分辨率的瓶颈&lt;/h2>
&lt;p>NanoVLM 的基础版本将每张图 resize 到 384×384，经 SigLIP 编码为 729 个 visual token。这对大多数自然图像够用——但遇到高分辨率图像（文档、OCR、大场景）时，细节会被压缩到不可辨认。&lt;/p>
&lt;p>一个具体的例子：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>原始图像: 1920×1080 的截图（包含文字）
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓ resize 到 384×384
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>丢失了 (1920×1080) / (384×384) = 14× 的像素信息
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ↓
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>文字模糊到 LLM 无法识别
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>AnyRes 的思路很直接——&lt;strong>不要压缩整张图，而是把大图切成多个小图，每个小图保持清晰&lt;/strong>。&lt;/p>
&lt;h2 id="核心算法">核心算法&lt;/h2>
&lt;h3 id="处理流程">处理流程&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>原图 (如 1200×800, AR=1.5)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├─ Step 1: 选 grid → 2×2（4 tiles）
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├─ Step 2: 生成缩略图
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │ resize → 384×384 → 729 tokens（全局上下文）
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> └─ Step 3: 切分 + 编码 tiles
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 原图 → resize_to_fit(768×768) → 切成 4 个 384×384 tile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tile[0,0] → SigLIP → 729 tokens
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tile[0,1] → SigLIP → 729 tokens
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tile[1,0] → SigLIP → 729 tokens
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tile[1,1] → SigLIP → 729 tokens
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ─────────
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 总计: 5 × 729 = 3645 tokens
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关键细节：&lt;strong>缩略图保留全局上下文，tiles 保留局部细节&lt;/strong>。两者互补——缩略图告诉 LLM&amp;quot;这是一张包含文字和图表的信息图&amp;quot;，tiles 告诉 LLM 文字具体写了什么。&lt;/p></description></item><item><title>NanoVLM-LLaVA</title><link>https://ganko.asia/posts/nanovlm-llava/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/nanovlm-llava/</guid><description>&lt;blockquote>
&lt;p>总结了NanoVLM（LLaVA格式）的背景、原理、核心代码、实现细节。最开始只是LLaVA思想的初步实现，即使用一个线性层（或MLP）将视觉特征转换为文本特征，或者说是将视觉特征和文本特征对齐，后边会慢慢加入LLaVA-1.5、LLaVA-NeXT、LLaVA-OneVision的思想。&lt;/p>&lt;/blockquote>
&lt;h2 id="llava">LLaVA&lt;/h2>
&lt;p>LLaVA 最初的结构如下:&lt;/p>
&lt;p>&lt;img src="https://ganko.asia/images/NanoVLM/image.png" alt="alt text">&lt;/p>
&lt;p>其中， Xv为输入图像，而Xq为输入文本指令。 Xv经过冻结的预训练视觉编码器（例如CLIP的视觉编码器）转换为视觉特征, 又进一步经过一个简单的线性层W转换为文本特征,便可和文本指令特征Hq一起送入LLM进行处理。&lt;/p>
&lt;p>LLaVA的训练目标为LM:&lt;/p>
$$
p(\mathbf{X}_{\mathrm{a}} \mid \mathbf{X}_{\mathrm{v}}, \mathbf{X}_{\mathrm{instruct}})
= \prod_{i=1}^{L} p_{\boldsymbol{\theta}}(x_i \mid \mathbf{X}_{\mathrm{v}}, \mathbf{X}_{\mathrm{instruct}}, \mathbf{X}_{\mathrm{a}, &lt; i})
$$&lt;p>即基于当前图像、历史指令、历史答复预测新一轮的答复。整个训练过程包含两步：&lt;/p>
&lt;p>步骤1: 固定Vision Encoder和LLM，预训练Projection 以实现图像和文本模态对齐；&lt;/p>
&lt;p>步骤2: 放开LLM，进行端到端的训练。&lt;/p>
&lt;h4 id="原始-llava-10-的具体配置">原始 LLaVA 1.0 的具体配置&lt;/h4>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>组件&lt;/th>
&lt;th>配置&lt;/th>
&lt;th>参数量&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Vision Encoder&lt;/td>
&lt;td>CLIP ViT-L/14@224²&lt;/td>
&lt;td>~300M&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Projector&lt;/td>
&lt;td>单层 Linear (1024→4096)&lt;/td>
&lt;td>~4.2M&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LLM&lt;/td>
&lt;td>Vicuna-7B/13B&lt;/td>
&lt;td>7B/13B&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Vision Encoder&lt;/strong>：使用 OpenAI 预训练的 CLIP ViT-L/14，输入分辨率为 224×224。patch_size=14，因此每张图产生 $(224/14)^2 = 256$ 个 patch token + 1 个 CLS token，每个 token 维度为 1024。视觉编码器在&lt;strong>整个训练过程中完全冻结&lt;/strong>。&lt;/p></description></item><item><title>多卡并行训练和微调技术</title><link>https://ganko.asia/posts/%E5%A4%9A%E5%8D%A1%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E5%92%8C%E5%BE%AE%E8%B0%83%E6%8A%80%E6%9C%AF/</link><pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E5%A4%9A%E5%8D%A1%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E5%92%8C%E5%BE%AE%E8%B0%83%E6%8A%80%E6%9C%AF/</guid><description>&lt;blockquote>
&lt;p>这是使用 Google DeepResearch 生成的偏理论分析报告，内容基于2026/4/27之前的公开资料和技术文献，主要是方便自己学习，准确性和时效性可能无法完全保证。&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="第一章-深度学习分布式训练的底层基石显存与通信的博弈">第一章 深度学习分布式训练的底层基石：显存与通信的博弈&lt;/h2>
&lt;p>随着大语言模型（LLM）参数规模从十亿级别飙升至万亿级别，深度学习的训练与微调已经彻底演变为一项复杂的系统工程。在这一演进过程中，单张图形处理器（GPU）的显存容量与计算能力已无法满足动辄数千吉字节（GB）的内存需求，多卡并行架构成为必然选择。&lt;/p>
&lt;p>在多卡分布式训练中，架构设计的核心挑战始终围绕着**“显存墙（Memory Wall）”&lt;strong>与&lt;/strong>“通信墙（Communication Wall）”**的博弈展开。&lt;/p>
&lt;h3 id="11-显存消耗模型解构">[1].1 显存消耗模型解构&lt;/h3>
&lt;p>要深刻理解分布式训练的演进，必须首先解构模型在训练过程中的显存消耗。在采用混合精度训练（Mixed Precision Training）及 Adam 优化器的情况下，每个模型参数通常需要消耗约 &lt;strong>20 字节&lt;/strong>的显存：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>模型状态（Model States）：&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>权重与梯度：&lt;/strong> 半精度（16-bit）各占用 [2] 字节（共 [4] 字节）。&lt;/li>
&lt;li>&lt;strong>权重与梯度副本：&lt;/strong> 全精度（32-bit）各占用 [4] 字节（共 [8] 字节）。&lt;/li>
&lt;li>&lt;strong>优化器状态：&lt;/strong> Adam 优化器的一阶与二阶矩估计状态各占用 [4] 字节（共 [8] 字节）。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>剩余消耗：&lt;/strong> 前向传播过程中产生的**残差状态（Residual States，即激活值 Activations）**和各类临时缓冲区，会随着批次大小（Batch Size）和序列长度呈线性甚至二次方增长。&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>示例：&lt;/strong> 一个 [75] 亿参数的模型，仅静态模型状态就需要消耗约 150GB 显存，远超单张 H100（80GB）的物理极限。&lt;/p>&lt;/blockquote>
&lt;h3 id="12-通信原语与同步机制">[1].2 通信原语与同步机制&lt;/h3>
&lt;p>在多 GPU 协同计算时，节点间必须通过特定的**集体通信原语（Collective Communications）**进行数据交互：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>基础原语：&lt;/strong> 包括广播（Broadcast）、收集（Gather）、分散（Scatter）以及规约（Reduce）。&lt;/li>
&lt;li>&lt;strong>核心同步机制：&lt;/strong> &lt;strong>全规约（All-Reduce）&lt;/strong>。它确保了所有 GPU 在反向传播后能够获得一致的梯度总和。&lt;/li>
&lt;/ol>
&lt;p>从底层实现来看，最优的 All-Reduce 操作通常被分解为两个连续步骤：&lt;strong>Reduce-Scatter（规约-分散）&lt;/strong> 与 &lt;strong>All-Gather（全收集）&lt;/strong>。理解这种分解机制是掌握高级状态切分策略（如 ZeRO 和 FSDP）的技术基石。&lt;/p></description></item><item><title>[Paper] Causal</title><link>https://ganko.asia/posts/causal/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/causal/</guid><description>&lt;h2 id="所有之前">所有之前&lt;/h2>
&lt;blockquote>
&lt;p>这篇文章是我在阅读因果理论在视觉方面应用相关论文时的笔记总结,通过这篇文章，我希望能够系统地梳理相关论文的核心方法和我的理解和思考。
后边到了写作的时候，增加了一些写作的参考。写作思路部分会按照普遍论文的结构进行-摘要、引言、相关工作、方法、实验、结论来总结写作思路，当然也会根据不同论文的特点进行调整。&lt;/p>&lt;/blockquote>
&lt;h2 id="tpami-a-causal-adjustment-module-for-debiasing-scene--graph-generation">[TPAMI] A Causal Adjustment Module for Debiasing Scene Graph Generation&lt;/h2>
&lt;h3 id="这篇论文想解决什么问题">这篇论文想解决什么问题？&lt;/h3>
&lt;p>这篇论文想解决场景图生成中对于长尾关系对的偏见问题，通过基于全局的统计量设计的一个后处理模块来调整模型的预测结果，从而提升模型在长尾关系对上的性能。&lt;/p>
&lt;p>传统的去偏方法（重采样、重加权、调整方法）只关注关系分布 R 的长尾问题，但它们忽略了一个更深层的因果链条：&lt;/p>
&lt;blockquote>
&lt;p>物体分布 O → 物体对分布 P → 关系分布 R :&lt;/p>
&lt;ul>
&lt;li>物体分布 O ：不同物体类别的频率（如&amp;quot;人&amp;quot;很常见，&amp;ldquo;大象&amp;quot;很罕见）&lt;/li>
&lt;li>物体对分布 P ：两个物体共同出现的频率（如&amp;lt;人, 椅子&amp;gt;很常见，&amp;lt;人, 大象&amp;gt;很罕见）&lt;/li>
&lt;li>关系分布 R ：具体关系的频率&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>仅仅建模 O→P 是不够的,直观上，如果&amp;quot;人&amp;quot;和&amp;quot;树&amp;quot;都是高频物体，按 O→P 的逻辑，&amp;lt;人, 树&amp;gt;应该是最常见的物体对。但现实中，&amp;lt;人, 衬衫&amp;gt;比&amp;lt;人, 树&amp;gt;更常见，因为人和衬衫的共现（Co-occurrence）概率更高。&lt;/p>
&lt;p>论文提出了 Mediator-based Causal Chain Model (MCCM)，将因果链修正为：
&lt;/p>
$$ O→中介：共现分布 C​​→P→R $$&lt;h3 id="核心方法">核心方法&lt;/h3>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/Causal/image.png" alt="方法图示" />
&lt;/p>
&lt;p>原理:从因果推断中引入 Average Treatment Effect (ATE) 概念，用于指导调整因子的学习。&lt;/p>
&lt;p>反事实问题：如果能把物体对分布 P 从&amp;quot;高频状态&amp;rdquo;（p ）改为&amp;quot;低频状态&amp;quot;（p0​ ），模型的预测会如何变化？&lt;/p>
&lt;p>公式 20 展示了 CAModule 如何估计这种反事实效应：
&lt;/p></description></item><item><title>CS336 Lecture 7-8：Parallelism</title><link>https://ganko.asia/posts/cs336-lecture-7-8-parallelism/</link><pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-lecture-7-8-parallelism/</guid><description>&lt;h2 id="本篇主题">本篇主题&lt;/h2>
&lt;p>这两节Lecture都是关于并行训练的，主要内容包括：&lt;/p>
&lt;ul>
&lt;li>理解训练超大模型时系统层面的复杂性&lt;/li>
&lt;li>掌握不同的 parallelization paradigms，以及为什么人们通常会同时使用多种并行方式&lt;/li>
&lt;li>了解大规模训练任务通常是如何进行的&lt;/li>
&lt;/ul>
&lt;h2 id="lecture-7---parallelism-1">Lecture 7 - Parallelism 1&lt;/h2>
&lt;p>单块GPU无法满足SCALING的需求，必须使用多块GPU进行训练,所以我们需要Multi-GPU、Multi-Machine的并行训练方法，如下图所示：&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/并行.jpg" alt="Parallelism 架构" />
&lt;/p>
&lt;p>首先讲了一些Basic Concepts：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>All Reduce&lt;/strong>：通信操作，所有参与的进程都将输入数据进行规约（如求和、最大值等）后，将结果分发给所有进程。常用于分布式训练中的梯度同步。&lt;/li>
&lt;li>&lt;strong>Broadcast&lt;/strong>：通信操作，数据从一个进程发送到所有其他进程。常用于分布式训练中的分发模型参数或者初始化数据。&lt;/li>
&lt;li>&lt;strong>All Gather&lt;/strong>：通信操作，所有参与的进程将各自的数据发送给所有其他进程，最终每个进程都获得所有数据的集合。常用于分布式训练中的收集模型输出或者中间结果。&lt;strong>和All Reduce的区别在于，All Reduce会对数据进行规约操作（如求和），而All Gather只是简单地收集数据，不进行任何计算。&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Reduce Scatter&lt;/strong>：通信操作，所有参与的进程将各自的数据发送给所有其他进程，并对数据进行规约操作（如求和），最终每个进程都获得规约后的结果的一部分。常用于分布式训练中的分布式梯度更新。&lt;/li>
&lt;/ul>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/basic.jpg" alt="Basic Concepts" />
&lt;/p>
&lt;p>了解了初始知识之后，可以正式进入核心部分，不同的并行方式：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Data Parallelism&lt;/strong>：最早的并行方式，模型复制到每个GPU上，每个GPU处理不同的数据batch，计算梯度后进行同步更新。优点是实现简单；缺点是通信开销大，尤其是模型参数较大时。
假设计算一个 SGD：我们会把 B 大小下的 batch 分给 M 个不同的机器，然后交换梯度去同步计算。这种情况对于 Compute scaling，每个 GPU 计算 B/M 个数据（不错！）；对于 Communication overhead，每个 batch 需要转移两次梯度（发送和接受）；对于 Memory scaling，完全没有，每个 GPU 都需要复制一次模型参数。
早期的data parallelism问题是只缓解了计算压力，内存压力没有缓解，需要每个GPU都复制一份模型参数，通信压力也很大。
Zero[HTTPS://arxiv.org/pdf/1910.02054]可以解决这个问题，核心的思想是将模型的state（参数和优化器状态）分布在不同的GPU上，每个GPU只存储模型的一部分，这样可以显著减少每个GPU的内存占用，同时通过通信操作来同步更新模型参数。
ZeRO分三个阶段：&lt;/li>
&lt;/ul>
&lt;ol>
&lt;li>&lt;strong>ZeRO-1&lt;/strong>：主要聚焦于 optimizer state sharding。把 optimizer state（first + second moments）分给每个 GPU，每个 GPU 都有 parameters + gradients，负责更新一部分 params。
每个 GPU 根据分配到的 batch 子集计算完整的梯度，此时只拥有局部梯度
利用 Reduce-Scatter 将所有 GPU 的局部梯度汇总并分散到每个设备上，现在每个 GPU 只持有全局梯度的一部分
每个 GPU 利用局部梯度和 optimizer state 更新该部分参数
利用 AllGather 将所有 GPU 的部分参数收集并分发给所有设备，确保每个 GPU 拥有完整的参数。
这种方法的通信开销并没有增加，而且 memory 减少了接近四倍（优化器状态是fp32，参数是fp16）。&lt;/li>
&lt;/ol>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/zero-1.jpg" alt="ZeRO-1" />
&lt;/p></description></item><item><title>Pytorch-Tricks</title><link>https://ganko.asia/posts/pytorch-tricks/</link><pubDate>Tue, 07 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/pytorch-tricks/</guid><description>&lt;blockquote>
&lt;p>&lt;strong>写在前面&lt;/strong>：Pytorch 内容繁杂，实验中用到的技巧与机制若不及时记录，容易遗忘并导致重复造轮子。本文档用于记录 Pytorch 的相关技巧与机制，将持续更新，方便后续查阅。&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="动态计算图">动态计算图&lt;/h2>
&lt;h3 id="缘起">缘起&lt;/h3>
&lt;p>在一次实验日志中，发现一个固定的 CNN 模块推理时间存在较大波动。排查后发现是数据流水线卡顿或 GPU 内存管理抖动所致，但也因此注意到了 Pytorch 的&lt;strong>动态计算图&lt;/strong>机制。&lt;/p>
&lt;blockquote>
&lt;p>Pytorch 在每次前向传播时都会重新构建计算图，这意味着每次前向传播都会产生额外开销，尤其在模型结构复杂或输入数据变化较大时，可能导致推理时间波动。&lt;/p>&lt;/blockquote>
&lt;p>具体而言：&lt;/p>
&lt;ul>
&lt;li>每次前向传播，即便模型结构未变，Pytorch 仍会依据当前输入数据和模型结构重建计算图。&lt;/li>
&lt;li>若输入数据形状或模型结构发生变化，计算图会重新构建，进而引发性能波动。&lt;/li>
&lt;/ul>
&lt;h3 id="可能导致性能波动的情况">可能导致性能波动的情况&lt;/h3>
&lt;h4 id="1-条件分支结构">1. 条件分支结构&lt;/h4>
&lt;p>模型中包含数据依赖的条件分支（如 &lt;code>if&lt;/code> 语句）时，不同前向传播可能执行不同计算路径，导致计算图结构变化。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">BadEncoder&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self, x):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> x&lt;span style="color:#f92672">.&lt;/span>sum() &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>: &lt;span style="color:#75715e"># 数据依赖的条件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>heavy_conv(x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">else&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>light_conv(x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="2-变长序列">2. 变长序列&lt;/h4>
&lt;p>处理变长序列（如 RNN 或 Transformer）时，每次输入长度可能不同，导致计算图结构变化。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">BadRNN&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self, x):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(x&lt;span style="color:#f92672">.&lt;/span>size(&lt;span style="color:#ae81ff">1&lt;/span>)): &lt;span style="color:#75715e"># 依赖输入序列长度&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>rnn_cell(x[:, i, :], x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="3-其他情况">3. 其他情况&lt;/h4>
&lt;ul>
&lt;li>动态形状&lt;/li>
&lt;li>随机性操作&lt;/li>
&lt;li>稀疏操作&lt;/li>
&lt;/ul>
&lt;h3 id="解决方案">解决方案&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>使用静态计算图&lt;/strong>：若模型结构固定，可借助 TorchScript 或 ONNX 转换为静态计算图，避免每次前向传播都重新构建。&lt;/li>
&lt;li>&lt;strong>Padding + Mask&lt;/strong>：对于变长序列，采用填充至统一长度，并利用 mask 标识有效部分，保持计算图结构一致。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="模型训练推理速度分析与优化">模型训练/推理速度分析与优化&lt;/h2>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>修改模型与训练代码后发现速度明显下降。排查发现数据加载耗时过长，遂将 DataLoader 的在线预处理改为离线处理。但模型推理速度仍慢于基线，后续需进一步优化。&lt;/p></description></item><item><title>CS336 Lecture 2: Resource Accounting</title><link>https://ganko.asia/posts/cs336-lecture2/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-lecture2/</guid><description>&lt;h2 id="本讲主线">本讲主线&lt;/h2>
&lt;p>这节课围绕一个核心问题展开：&lt;strong>如何精确估算训练成本&lt;/strong>。主要分为三块：&lt;/p>
&lt;ul>
&lt;li>内存占用&lt;/li>
&lt;li>FLOPs 估算&lt;/li>
&lt;li>模型与训练配置&lt;/li>
&lt;/ul>
&lt;p>这和 Lecture 1 提到的“效率优先”直接相关。&lt;/p>
&lt;h3 id="例题70b-模型训练时长">例题：70B 模型训练时长&lt;/h3>
&lt;p>问题：使用 1024 张 H100，在 15T tokens 上训练一个 70B 模型，需要多久？&lt;/p>
&lt;p>根据 Transformer 常用训练量估算公式（$6 \times$ 参数量 $\times$ token 数）：&lt;/p>
$$ \text{总 FLOPs} = 6 \times 70 \times 10^9 \times 15 \times 10^{12} = 6.3 \times 10^{24}\,\text{FLOPs} $$&lt;p>单卡 H100（BF16）理论性能约为 $2 \times 10^{15}$ FLOPs/s。若考虑大模型训练实际效率约为 30%，则单卡有效 FLOPs/s 为：&lt;/p>
$$ 0.3 \times 2 \times 10^{15} = 6 \times 10^{14}\,\text{FLOPs/s} $$&lt;p>总时长：&lt;/p>
$$ \text{总时间} = \frac{\text{总 FLOPs}}{\text{每秒有效 FLOPs} \times \text{GPU 数量}} = \frac{6.3 \times 10^{24}}{6 \times 10^{14} \times 1024} $$&lt;p>
约等于 &lt;strong>119 天&lt;/strong>。&lt;/p></description></item><item><title>CS336 Lecture 3-4: Architectures, Hyperparameters, and MoE</title><link>https://ganko.asia/posts/cs336-lecture3-architectures-hyperparameters/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-lecture3-architectures-hyperparameters/</guid><description>&lt;h2 id="本讲主线">本讲主线&lt;/h2>
&lt;blockquote>
&lt;p>老师推荐了 The Illustrated Transformer 作为辅助材料。&lt;/p>&lt;/blockquote>
&lt;p>这节课基于 Tatsu H 对 2017-2025 年经典模型的统计，讨论两个问题：&lt;/p>
&lt;ol>
&lt;li>不同模型在架构与超参数上有哪些共性与分歧？&lt;/li>
&lt;li>这些演化背后的工程动机是什么？&lt;/li>
&lt;/ol>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/model_list.png" alt="模型列表" />
&lt;/p>
&lt;h2 id="架构与超参数观察">架构与超参数观察&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Pre-Norm vs Post-Norm&lt;/strong>
几乎所有现代 LLM（BERT 这类早期模型除外）都采用 Pre-Norm。核心原因是训练更稳定，梯度路径更顺畅。近年还出现了 double norm 等变体（如 Grok、Gemma 2），但尚未完全普及。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>LayerNorm vs RMSNorm&lt;/strong>
RMSNorm 不计算均值，只做均方根归一化，计算更简单。表面上看节省 FLOPs 不多，但在真实系统中，norm 的时间开销往往受 data movement 影响明显，因此 RMSNorm 的工程收益更像是在缓解内存墙，而不仅是减少算术量。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>激活函数演化&lt;/strong>
从早期 ReLU，到 GPT 系列常见的 GeLU，再到近年广泛采用的 SwiGLU（门控激活变体）。门控结构通过逐元素调制，提升了表达能力与训练效率的折中表现。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>串行层与并行层&lt;/strong>
传统 Transformer block 以串行堆叠为主。并行 block（如部分 GPT-J 设计）存在，但总体采用度不高。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>位置编码路线&lt;/strong>
Sine/Absolute/Relative 都在不同阶段被主流模型采用。近年 RoPE（rotary position embeddings）几乎成为事实标准之一。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>FFN 维度比（ffn dim : model dim）&lt;/strong>
传统经验常用 4 倍宽度；在 GLU 系列激活流行后，很多模型会选在 2.5-3.5 区间（常见约 8/3），以平衡参数规模与表达能力。&lt;/p></description></item><item><title>CS336-写在所有之前</title><link>https://ganko.asia/posts/cs336-%E5%86%99%E5%9C%A8%E6%89%80%E6%9C%89%E4%B9%8B%E5%89%8D/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-%E5%86%99%E5%9C%A8%E6%89%80%E6%9C%89%E4%B9%8B%E5%89%8D/</guid><description>&lt;p>CS336 是一门很好的课，但是很多内容都比较基础，或者在网上已经有很多资源了。&lt;/p>
&lt;p>2026/04/06:我学到了Lecture4，目前来看，CS336的精华内容还是在Lab上面，如果想要系统学习LLM的训练细节，建议直接看Lab的内容，Lecture部分可以作为辅助材料来理解一些概念和背景知识。&lt;/p>
&lt;p>2026/04/09：Lecture4之后因为对并行训练的兴趣，直接跳到了Lecture7-8，感觉内容非常有价值，值得细看一下lecture视频或者讲义，精华在于不同并行方式的介绍和分析，在Lecture8里有一些简单的通信操作代码示例，帮助理解。&lt;/p></description></item><item><title>CS336 Lecture 1: Overview and Tokenization</title><link>https://ganko.asia/posts/cs336-lecture1/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/cs336-lecture1/</guid><description>&lt;h2 id="课程导读">课程导读&lt;/h2>
&lt;p>这门课的讲义基于 notebook 组织，不同章节通过函数模块化展开。&lt;/p>
&lt;p>开场老师提出了一个很尖锐的问题：&lt;strong>研究者正在与底层技术逐步脱节&lt;/strong>。他给了一个时间线：&lt;/p>
&lt;ul>
&lt;li>八年前，研究者会自己补充数据并训练模型；&lt;/li>
&lt;li>六年前，研究者还会下载模型后进行 fine-tune；&lt;/li>
&lt;li>现在，很多人直接向闭源模型（GPT-4/Claude/Gemini）提问。&lt;/li>
&lt;/ul>
&lt;p>这虽然有些夸张，但确实反映了趋势：模型能力提升后，很多基础环节被“封装”了。老师强调：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;Full understanding of this technology is necessary for fundamental research&amp;rdquo;&lt;/strong>&lt;/p>&lt;/blockquote>
&lt;p>随着模型规模持续增大，训练中的计算压力正在从 Attention 逐步转向 FFN。&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/计算压力转换.png" alt="计算压力转换" />
&lt;/p>
&lt;h3 id="课程收获">课程收获&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Mechanics&lt;/strong>：系统如何工作（如 Transformer 结构、GPU 并行方式）&lt;/li>
&lt;li>&lt;strong>Mindset&lt;/strong>：如何最大化利用硬件与内存，如何看待 scaling laws&lt;/li>
&lt;li>&lt;strong>Intuition&lt;/strong>：哪些数据和建模决策更可能带来更好结果&lt;/li>
&lt;/ul>
&lt;p>老师也指出一个常见误解：只要堆算力，模型就会自动变好。他给出的观点是：&lt;strong>准确率 = 效率 × 资源&lt;/strong>。&lt;/p>
&lt;p>在数据和资源固定时，效率决定了上限。&lt;/p>
&lt;p>老师将近年的 LLM 工作大致分成两类：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>闭源路线&lt;/strong>：以 GPT 系列为代表，最早系统性拥抱 Scale，但细节封闭。&lt;/li>
&lt;li>&lt;strong>开放权重路线&lt;/strong>：以 Qwen 等 open-weight 模型为代表，拥抱 Scale 的同时提升开放度，但常见情况是只公开部分训练细节，数据与失败案例仍不完整。&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="tokenization">Tokenization&lt;/h2>
&lt;p>为什么需要 tokenization？因为 LLM 在 token 序列上建模概率分布，我们需要把原始字符串编码为 token，并保证可逆解码。&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/tokenization.png" alt="tokenization" />
&lt;/p>
&lt;p>🔗 &lt;strong>Tokenization 可视化工具&lt;/strong>: &lt;a href="https://tiktokenizer.vercel.app/?encoder=gpt2">tiktokenizer.vercel.app&lt;/a>&lt;/p>
&lt;p>常见 tokenization 方法：&lt;/p></description></item><item><title>博客网站优化日志</title><link>https://ganko.asia/posts/%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99%E4%BC%98%E5%8C%96%E6%97%A5%E5%BF%97/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99%E4%BC%98%E5%8C%96%E6%97%A5%E5%BF%97/</guid><description>&lt;hr>
&lt;h2 id="-2026-04-03">📅 2026-04-03&lt;/h2>
&lt;p>✅ 已完成工作&lt;/p>
&lt;ul>
&lt;li>&lt;strong>环境搭建&lt;/strong>：Hugo+PaperMod 部署。&lt;/li>
&lt;li>&lt;strong>域名申请&lt;/strong>：ganko.asia 申请。&lt;/li>
&lt;/ul>
&lt;p>🚧 进行中（等待审核）&lt;/p>
&lt;ul>
&lt;li>&lt;strong>域名备案/审核&lt;/strong>：域名实名审核/备案状态，不能通过自定义域名访问。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="-2026-04-04">📅 2026-04-04&lt;/h2>
&lt;ul>
&lt;li>头像发光效果，文章卡片悬浮效果。&lt;/li>
&lt;/ul>
&lt;h2 id="-2026-04-07">📅 2026-04-07&lt;/h2>
&lt;ul>
&lt;li>域名审核通过，绑定成功，使用Nginx+Certbot配置HTTPS。&lt;/li>
&lt;li>增加阅读的目录，直接跳转到文章不同部分。&lt;/li>
&lt;/ul></description></item><item><title>胡思乱想</title><link>https://ganko.asia/posts/%E8%83%A1%E6%80%9D%E4%B9%B1%E6%83%B3/</link><pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E8%83%A1%E6%80%9D%E4%B9%B1%E6%83%B3/</guid><description>&lt;blockquote>
&lt;p>这里用来记录一些无论是产品角度的想法，还是算法角度的想法，或者是一些其他的想法。总之就是一些胡思乱想，这里不会引用任何论文，我也不会去查找任何资料，完全是凭空想象的。也就是说，这里记录的内容可能完全是错误的，甚至是荒谬的，但我觉得有趣，所以就记录下来.&lt;/p>&lt;/blockquote>
&lt;h2 id="神奇的特征空间-2026-4-1">神奇的特征空间 2026-4-1&lt;/h2>
&lt;p>在这个神奇的特征空间中，同一物体的特征不再是无规律的，而是可以通过运算得到的，例如：&lt;/p>
&lt;ul>
&lt;li>一个朝向我可乐瓶的特征可以通过旋转得到一个背向我的可乐瓶的特征。&lt;/li>
&lt;li>一半可乐瓶的特征应该是contact另一半可乐瓶的特征得到完整可乐瓶的特征。&lt;/li>
&lt;/ul>
&lt;p>具体来说，就是一个可旋转，拼接，以及不同角度拼接的特征空间，如果可以的话，这个特征空间应该是三维的（不过很明显这里的特征不包括-一瓶水甜还是苦这种单从图片无法推测的属性）&lt;/p>
&lt;h2 id="vit和cnn都有的惰性问题依赖背景对主体进行识别-2026-4-18">VIT和CNN都有的惰性问题：依赖背景对主体进行识别 2026-4-18&lt;/h2>
&lt;p>在一些数据集中，模型可能会过度依赖背景信息来识别主体。例如，在一个包含大量猫的图片数据集中，模型可能会学会通过识别草地或室内环境来判断图片中是否有猫，而不是通过识别猫的特征。这种依赖背景的现象可能会导致模型在面对新的环境或背景时表现不佳，因为它没有真正学会识别主体的特征。&lt;/p>
&lt;p>找到哪些受上下文影响较大的特征，让模型仅通过这些特征识别，让总体的识别减去这些敏感特征的识别，效果会不会变好。因为从最近研究的因果角度来说，背景信息某种程度上也会影响主体的识别，所以完全去除背景信息可能也不是最好的选择，而是找到一个平衡点，让模型减去完全使用背景信息盲猜的结果，在因果图上相当于切断了背景信息对主体识别的直接影响，但保留了背景信息通过主体再影响识别的间接影响。&lt;/p>
&lt;blockquote>
&lt;p>补充:四月刷到了一篇关于解决VIT这个问题的论文，不过没看，不知道他用的什么方法（还是抽空看一下吧）;现在是5月26，这篇论文看了，笔记在&lt;a href="https://ganko.asia/posts/read_vit_lazy_aggregation/">vit_lazy_aggregation&lt;/a>但是还是有点不一样，和我想的有一点不一样，他还是在针对前景和背景这两个具体的块做，本质还是针对不同信息密度的区域做不同处理，有点像是任务导致的区别，分类任务本质就是要找到主体，而类分割任务要的是主要根据自身区域并一定程度上参考其他区域能给予的辅助信息来预测。（讲的好像不是很好，不过我暂时没心思做这么大的任务，说笼统一点就是，不分主体背景，模型就是根据那片区域本身和上下文区域的辅助信息来做预测，无论是分类任务还是类分割任务，这是一个完全符合人类逻辑的因果链条）&lt;/p>&lt;/blockquote>
&lt;h2 id="vlm对一个图像中不同区域的识别问题">VLM对一个图像中不同区域的识别问题&lt;/h2>
&lt;p>论文的方案想用VLM做标注，因为用原有数据集的位姿轨迹自监督效果并不好，主要是想让VLM去评估一个off-road场景下不同区域的Risk，方案开始是超像素分割-&amp;gt;合并并区域标号-&amp;gt;VLM评估每个区域的Risk。在用的时候发现，区域数目20-30（测的22）的时候，VLM会有自己编造的区域，会自己编造到30个区域。
原因可能感觉有很多：&lt;/p>
&lt;ul>
&lt;li>一个是图像的分辨率低，为了省钱，图像分辨率我用的是960*640，可能VLM觉得这个分辨率太低了，无法识别出足够的细节。&lt;/li>
&lt;li>第二个是超像素分割的问题，没有仔细调超像素的参，分割出很多长条状，形状极不规则的区域，增大了VLM的识别难度。&lt;/li>
&lt;li>第三个就是老生常谈的VLM根本没办法真正理解图片。
最终没采用VLM标注的方案，因为试了每个区域一个一个送，发现标完所有近两万张图的花费太高了，不知道老师会不会报销。&lt;/li>
&lt;/ul>
&lt;h2 id="相对数据会比绝对数据更有用吗-2026-5-7">相对数据会比绝对数据更有用吗 2026-5-7&lt;/h2>
&lt;blockquote>
&lt;p>这个idea已经总结成了一个确切的方案了，对比了一些现有的工作感觉值得做，打算做完现在这个和老师提一下，现在先自己做一些小范围的验证，反正有了ai之后做的快了很多。&lt;/p>&lt;/blockquote>
&lt;p>突然想起来毕设的任务里有一个小的深度估计器，还有当时对输入输出的分析，当时对比好的结果和坏的结果，发现好的定位结果的文本描述中相对位置的描述特别多，例如“在左边”、“在右边”、“在上面”、“在下面”等等，而坏的定位结果的文本描述中相对位置的描述特别少，更多的是绝对位置的描述，例如“在某个车右边0.5米处”，好像答辩的时候也提过这个问题，觉得相对位置的描述可能更有用。这辈子还有机会做这个问题吗？感觉这个问题挺有意思的，可能也挺有用的，如果能证明相对位置的描述更有用的话，可能会对定位任务优化有用，或许已经有人做了呢？一个本科毕设能分析出啥好东西来。&lt;/p>
&lt;h2 id="嘴型特征作为分布中心猜测文本和真实文本以他为中心-2026-5-15">嘴型特征作为分布中心，猜测文本和真实文本以他为中心 2026-5-15&lt;/h2>
&lt;p>这只是个猜测，这个点从一些up主一个人说话不出声，另一个人猜什么并和第三个人打电话沟通来的，我感觉，猜的文本很明显不是瞎猜的，是根据嘴型（主要），对方的性格，当时的情景等（不过要是一个人纯瞎说肯定没法猜了）。这个肯定可以用在从嘴型猜文本这个任务上，但是这个任务不知道有啥用（偷拍别人视频然后恢复人家说话来偷听？），我想的是之前做过语音驱动数字人（嘴型），在刚刚的猜测链条上加一个语音并且反过来，文本增强（如果能搞到这个分布的话增强更好）语音驱动数字人。还有一个，直接从嘴型猜文本很难，加上语音（语音本身直接就可以）相当于把之前以嘴型为中心的分布进行约束得到最终的文本，那如果用不同的语音约束呢。&lt;/p>
&lt;p>这个想法真怪，但是这个以嘴型特征分布为中心，我确信应该是对的，只是不知道怎么用。&lt;/p>
&lt;h2 id="llm生成模型来增强数据集来达到提升很多不同任务模型的因果推断能力-2026-5-24">LLM+生成模型来增强数据集来达到提升很多不同任务模型的因果推断能力 2026-5-24&lt;/h2>
&lt;p>以图像分类任务为例，假设我们现在有一个模型，想提升它的因果推断能力.首先我们需要知道，原本的错误的因果链是什么，例如在图像分类任务中，模型可能过度依赖背景信息来识别主体，那么这个错误的因果链就是背景信息→主体识别。我们想要提升模型的因果推断能力，就需要打破这个错误的因果链，让模型学会真正识别主体的特征，而不是依赖背景信息。我们不通过理论的方法来打破这个因果链，依然通过数据的方式。动机是，对于人类来说，其实我们也有很多错误的因果认知，不过人类可以在经由他人指出错误的因果认知之后，直接修改这个因果链，直接把错误的因果链改成正确的因果链，而不需要通过大量的数据来重新学习这个因果链。 但是对于模型来说，没有直接修改因果链这个说法，除非模型本身显示构建了，所以我们只能通过数据来间接修改这个因果链。&lt;/p>
&lt;p>大概的方案可能是，首先对输入数据进行全方位的结构化描述，然后根据预测结果进行分类，分为正确的预测结果和错误的预测结果两类，因为之前的描述很结构化，可以使用自动化工具来构建出模型的认知因果链，例如如果观测到，模型对一个猫的预测正确的描述中，大量的背景描述相似，并且错误预测中背景描述和正确预测的背景描述差异较大，那么我们就可以推断出模型可能过度依赖背景信息来识别主体。&lt;/p>
&lt;p>接下来我们就可以针对这个错误的因果链，构建一个新的数据集，这个数据集中的图像会有更多的背景变化，例如同一只猫在不同的背景下出现，这样模型就需要学会真正识别猫的特征，而不是依赖背景信息来识别猫了。通过这样的方式，我们就可以提升模型的因果推断能力，让模型学会真正识别主体的特征，而不是依赖背景信息来识别主体了。&lt;/p>
&lt;p>这个方案不会提出任何具体的模型结构和针对任何任务，而是一个通用的方案，可以应用于很多不同的任务，例如图像分类、目标检测、语义分割等等。通过这个方案，我们可以提升很多不同任务模型的因果推断能力。但是有个前提是，我们需要能够生成新的输入数据和确切的标签数据，对于分类任务来说很简单，例如我们可以生成同一只猫在不同背景下的图像，并且标签仍然是猫。对于其他任务来说可能会更复杂一些，例如目标检测，我们需要生成同一只猫在不同背景下的图像，并且标签需要包含猫的位置和大小等信息，这可能需要一些更复杂的生成策略实现。&lt;/p>
&lt;h2 id="人类直觉和ai的联系-2026-6-5">人类直觉和AI的联系 2026-6-5&lt;/h2>
&lt;p>很明显，上面idea很多都很直觉，我发现很多现有的领域/任务/方法都和人类有一些联系。这也让我重新审视一些之前习以为常的做法，例如特征金字塔实际上做的是，人看整体、看局部（他是同时看的，那如果是看了整体之后再看局部会更好还是更差）&lt;/p>
&lt;h3 id="放大图片但不增加分辨率">放大图片但不增加分辨率&lt;/h3>
&lt;p>在我看不清一个图片的时候，我会放大，但是实际上图片的分辨率并没有提高，这实际上是人类视觉系统与计算机视觉在处理有限信息时的区别。已经有很多工作有这种思想了，主要在于怎么“放大”，“放大”的本质是：用固定的感知资源去“扫描”一个更小的空间范围，从而提高该区域的信息采样密度。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>空间注意力机制：模型学出一个“关注度热图”（如Transformer中的注意力权重），然后让后续层只对高权重区域进行精细计算，其他区域粗略处理，模拟人类聚焦的思想。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>多尺度推理 + 空间插值: 模拟放大并重新看的思想，将图像（或特征图）的一个局部区域通过双线性插值等操作“物理放大”到原来尺寸，再送入模型进行二次判断。虽然插值不增加信息，但它让后续的卷积核能够在该区域上用更多的参数去扫描，相当于人类眼球在局部区域做更多扫视。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>递归/循环放大 (Recursive Zoom)：模型反复对自己生成的“放大预测”进行再分析，逐轮修正。例如，先用低分辨率图像得到一个粗糙的语义图，然后将其作为先验，引导对原始低分辨率图像的第二次“注意力扫描”。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>特征金字塔 (Feature Pyramid Networks)：模型从原始图像中提取多尺度的特征图（例如原图的 1/4, 1/8, 1/16 大小）。高层特征感受野大，负责看整体；低层特征分辨率高，负责看细节。在进行推理时，融合高低层信息，相当于同时对全图（宏观）和局部（微观）进行“放大观察”。&lt;/p>
&lt;/li>
&lt;/ul></description></item><item><title>NanoGPT</title><link>https://ganko.asia/posts/nanogpt/</link><pubDate>Mon, 24 Nov 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/nanogpt/</guid><description>&lt;blockquote>
&lt;p>所有之前:这篇是关于NanoGPT项目的核心代码的总结和理解，我会持续把主流技术加入到这个项目中，并对核心代码进行解释。完整项目代码需要查询&lt;a href="https://github.com/JialeChe/NanoGPT.git">NanoGPT&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;h2 id="模型架构">模型架构&lt;/h2>
&lt;h3 id="base">Base&lt;/h3>
&lt;p>最基础的模型架构是一个Decoder-only的Transformer模型，代码实现参考&lt;a href="https://ganko.asia/posts/codebymyself/">CodeByMyself&lt;/a>,在CodeByMyself的基础上，使用了更现代化的Rope位置编码和SwiGLU激活函数， 并且加入了Moe用于和FFN对比，可在配置文件中选择是否使用Moe。部分代码如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># swiglu&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ffn_swiglu&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self, d_model, d_hidden, dropout&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.1&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super()&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#第一个 Linear 输出 2 * d_hidden&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_gate_up &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model, &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">*&lt;/span> d_hidden) &lt;span style="color:#75715e">#同时生成 gate 和 up&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_down &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_hidden, d_model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>dropout &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Dropout(dropout)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self, x):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># x: [B, L, d_model]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gate_up &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>w_gate_up(x) &lt;span style="color:#75715e"># [B, L, 2 * d_hidden]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gate, up &lt;span style="color:#f92672">=&lt;/span> gate_up&lt;span style="color:#f92672">.&lt;/span>chunk(&lt;span style="color:#ae81ff">2&lt;/span>, dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#75715e"># each: [B, L, d_hidden]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> swiglu_out &lt;span style="color:#f92672">=&lt;/span> F&lt;span style="color:#f92672">.&lt;/span>silu(gate) &lt;span style="color:#f92672">*&lt;/span> up &lt;span style="color:#75715e"># [B, L, d_hidden]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>w_down(self&lt;span style="color:#f92672">.&lt;/span>dropout(swiglu_out)) &lt;span style="color:#75715e"># [B, L, d_model]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> out
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># moe&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">moe&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self,n_expert,d_model,top_k&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>,dropout&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.1&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super()&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>d_model &lt;span style="color:#f92672">=&lt;/span> d_model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>n_expert &lt;span style="color:#f92672">=&lt;/span> n_expert
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>top_k &lt;span style="color:#f92672">=&lt;/span> top_k
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>dropout &lt;span style="color:#f92672">=&lt;/span> dropout
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>gate &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model,n_expert,bias&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">False&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>softmax &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Softmax(dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># self.experts = nn.ModuleList([ffn(self.d_model,self.d_model*4,dropout) for _ in range(n_expert)]) relu激活的expert&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>experts &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>ModuleList([ffn_swiglu(self&lt;span style="color:#f92672">.&lt;/span>d_model,self&lt;span style="color:#f92672">.&lt;/span>d_model&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>,dropout) &lt;span style="color:#66d9ef">for&lt;/span> _ &lt;span style="color:#f92672">in&lt;/span> range(n_expert)])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,x):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b,t,d &lt;span style="color:#f92672">=&lt;/span> x&lt;span style="color:#f92672">.&lt;/span>shape
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">assert&lt;/span> d &lt;span style="color:#f92672">==&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>d_model,&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;输入维度和moe设置维度不匹配&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x_flat &lt;span style="color:#f92672">=&lt;/span> x&lt;span style="color:#f92672">.&lt;/span>view(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>,d)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> N &lt;span style="color:#f92672">=&lt;/span> x_flat&lt;span style="color:#f92672">.&lt;/span>shape[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gate_logits &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>gate(x_flat)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> topk_weights,topk_indices &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>topk(gate_logits,self&lt;span style="color:#f92672">.&lt;/span>top_k,dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> topk_weights&lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>softmax(topk_weights)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>zeros_like(x_flat)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> i,expert &lt;span style="color:#f92672">in&lt;/span> enumerate(self&lt;span style="color:#f92672">.&lt;/span>experts):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> mask &lt;span style="color:#f92672">=&lt;/span> (topk_indices &lt;span style="color:#f92672">==&lt;/span> i)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> mask&lt;span style="color:#f92672">.&lt;/span>any():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> token_indices,expert_pos &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>where(mask)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> select_x &lt;span style="color:#f92672">=&lt;/span> x_flat[token_indices]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> expert_out &lt;span style="color:#f92672">=&lt;/span> expert(select_x)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> weights &lt;span style="color:#f92672">=&lt;/span> topk_weights[token_indices, expert_pos]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out&lt;span style="color:#f92672">.&lt;/span>index_add_(&lt;span style="color:#ae81ff">0&lt;/span>, token_indices, expert_out &lt;span style="color:#f92672">*&lt;/span> weights&lt;span style="color:#f92672">.&lt;/span>unsqueeze(&lt;span style="color:#ae81ff">1&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> out&lt;span style="color:#f92672">.&lt;/span>view(b,t,d)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">precompute_freqs_cis&lt;/span>(dim: int, end: int, theta: float &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">10000.0&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 预计算旋转角度的复数表示（cos + i*sin）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> freqs &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span> &lt;span style="color:#f92672">/&lt;/span> (theta &lt;span style="color:#f92672">**&lt;/span> (torch&lt;span style="color:#f92672">.&lt;/span>arange(&lt;span style="color:#ae81ff">0&lt;/span>, dim, &lt;span style="color:#ae81ff">2&lt;/span>)[: (dim &lt;span style="color:#f92672">//&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)]&lt;span style="color:#f92672">.&lt;/span>float() &lt;span style="color:#f92672">/&lt;/span> dim))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>arange(end, device&lt;span style="color:#f92672">=&lt;/span>freqs&lt;span style="color:#f92672">.&lt;/span>device)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> freqs &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>outer(t, freqs)&lt;span style="color:#f92672">.&lt;/span>float() &lt;span style="color:#75715e"># [end, dim//2]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> freqs_cos &lt;span style="color:#f92672">=&lt;/span> freqs&lt;span style="color:#f92672">.&lt;/span>cos()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> freqs_sin &lt;span style="color:#f92672">=&lt;/span> freqs&lt;span style="color:#f92672">.&lt;/span>sin()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> freqs_cos, freqs_sin &lt;span style="color:#75715e"># 分开存储更便于后续操作，不使用torch.complex类型，因为部分系统不支持&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SwiGLU激活函数的实现是通过将线性层的输出分成两部分，一部分作为gate，另一部分作为up，然后使用SILU函数对gate进行激活，并与up相乘得到最终的输出。&lt;/p></description></item><item><title>CodeByMySelf-Diffusion</title><link>https://ganko.asia/posts/codebymyself-diffusion/</link><pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/codebymyself-diffusion/</guid><description>&lt;blockquote>
&lt;p>所有之前：CodeByMySelf 系列之 Diffusion Models 的实现记录，变体不会在这篇里更新。&lt;/p>&lt;/blockquote>
&lt;h2 id="diffusion-models">Diffusion Models&lt;/h2>
&lt;h3 id="原理">原理&lt;/h3>
&lt;p>具体的一些公式推导请看李宏毅老师的视频：
&lt;a href="https://www.bilibili.com/video/BV1mLbQeRExa?t=0.0">李宏毅Diffusion&lt;/a>&lt;/p>
&lt;h3 id="基本概念">基本概念&lt;/h3>
&lt;p>（以图像生成为例）首先Diffusion的基本运作过程是，首先Sample出一个全是噪声的图片，然后经过一步一步的Denoise最终得到图片，Denoise的步数是事先确定好的。&lt;/p>
&lt;p>&lt;strong>在Diffusion中，深度学习模型的唯一作用就是预测噪声，其他过程均由数学公式推理得到&lt;/strong>&lt;/p>
&lt;p>进一步说，不同情况的噪声需要的处理肯定是不一样的，一个Denoise模型肯定无法做到处理不同的情况的噪声，因此Denoise模型需要一个“噪声严重程度”作为输入，在Diffusion中称为时间步。&lt;/p>
&lt;p>Denoise内部的工作是，&lt;strong>接受带Noise的图片，对噪声进行预测，然后使用带Noise的图片减去预测噪声那么就可以得到。&lt;/strong>&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/CodeByMyself/基本概念.png" alt="基本概念"/>
&lt;/p>
&lt;p>我们清楚Noise predictor模型的输入输出之后，该怎么训练这个模型呢？已知模型的输入-输出对是Noise图片加上“噪声程度”-Noise数据对，我们需要人为创造这个数据对出来，具体来说，从image list中拿一张图片，然后从GasuionN中采样出一张纯噪声的图片，加了一定的步数之后，就得到了很多数据对（Noise图片、时间步&amp;ndash;噪声），这个过程称为Diffusion Process。&lt;/p>
&lt;p>现在，已经可以从一个纯噪声得到一张图片，但是我们不能根据噪声随机生成图片，所以我们需要把文字考虑进来，让模型考虑进文字之后再预测噪声。&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/CodeByMyself/考虑text.png" alt="考虑文字"/>
&lt;/p>
&lt;h3 id="完整算法">完整算法&lt;/h3>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/CodeByMyself/pric.PNG" alt="完整算法"/>
&lt;/p>
&lt;p>首先是Training的过程，从immage list中取出一张干净的图，之后从1-T中随机取一个值作为时间步，然后从Gaussion中取样出一个noise，之后就是一步一步的梯度更新训练模型。这种方法和我们的想法有些不一样，我们想像中noise是一步一步加进去的，但是在实际中是一下子直接加进去的。&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/CodeByMyself/addnoise.png" alt="加噪过程"/>
&lt;/p>
&lt;p>具体的加噪公式推导过程如下：&lt;/p>
&lt;p align="center">
&lt;img src="https://ganko.asia/images/CodeByMyself/addnoise_formula.png" alt="加噪公式"/>
&lt;/p>
&lt;p>然后是推理过程，也就是Sampling这个过程。首先，采样得到一个纯噪声图片X_T，然后进行T次公式中的循环，$\epsilon_\theta$表示预测噪声的模型。&lt;/p>
&lt;p>但是为什么要加这个z噪声：每次都要重新采样出一个噪声，但是只有当t&amp;gt;1的时候.这个z的使用和生成语句中一个问题类似：为什么每次总要SAMPLE而不是直接取Mean（概率最大）？在&lt;a href="https://arxiv.org/abs/1904.09751">The curious case of nerual text degeneration&lt;/a>论文中有一个分析，当直接取Mean时候，会一直重复相同的回答和出现跳帧现象，并且他们分析得到人在写文章的时候并不会一定会选概率最大的词。&lt;/p>
&lt;h3 id="简单代码实现">简单代码实现&lt;/h3>
&lt;p>Diffusion已经有了许多变体，下面是一个简单的实现，变体不会在这篇里更新。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> torch &lt;span style="color:#f92672">import&lt;/span> nn
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> math
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch.nn.functional &lt;span style="color:#66d9ef">as&lt;/span> F
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> numpy &lt;span style="color:#66d9ef">as&lt;/span> np
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> time
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">WeightedLoss&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super(WeightedLoss,self)&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,pred,target,weighted&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1.0&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loss &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>_loss(pred,target)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> weighted_loss &lt;span style="color:#f92672">=&lt;/span> (loss &lt;span style="color:#f92672">*&lt;/span> weighted)&lt;span style="color:#f92672">.&lt;/span>mean() &lt;span style="color:#75715e"># mean by batch&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> weighted_loss
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">L1Loss&lt;/span>(WeightedLoss):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_loss&lt;/span>(self,pred,target):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>abs(pred &lt;span style="color:#f92672">-&lt;/span> target)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">L2Loss&lt;/span>(WeightedLoss):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_loss&lt;/span>(self,pred,target):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (pred &lt;span style="color:#f92672">-&lt;/span> target) &lt;span style="color:#f92672">**&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Losses &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;l1&amp;#39;&lt;/span>:L1Loss,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;l2&amp;#39;&lt;/span>:L2Loss
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SinusoidalPosEmb&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self,dim):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super(SinusoidalPosEmb,self)&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>dim &lt;span style="color:#f92672">=&lt;/span> dim
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,t):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 扩散模型时间步的位置编码公式和Transformer中的位置编码公式是类似的。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> device &lt;span style="color:#f92672">=&lt;/span> t&lt;span style="color:#f92672">.&lt;/span>device
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> half_dim &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>dim &lt;span style="color:#f92672">//&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> emb &lt;span style="color:#f92672">=&lt;/span> math&lt;span style="color:#f92672">.&lt;/span>log(&lt;span style="color:#ae81ff">10000&lt;/span>) &lt;span style="color:#f92672">/&lt;/span> (half_dim &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> emb &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>exp(torch&lt;span style="color:#f92672">.&lt;/span>arange(half_dim,device&lt;span style="color:#f92672">=&lt;/span>device) &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#f92672">-&lt;/span>emb)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> emb &lt;span style="color:#f92672">=&lt;/span> t[:,&lt;span style="color:#66d9ef">None&lt;/span>] &lt;span style="color:#f92672">*&lt;/span> emb[&lt;span style="color:#66d9ef">None&lt;/span>,:]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> emb &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cat((emb&lt;span style="color:#f92672">.&lt;/span>sin(),emb&lt;span style="color:#f92672">.&lt;/span>cos()),dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> emb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">extract&lt;/span>(a,t,x_shape):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> a: (T,) t: (B,) x_shape: (B,...)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_size &lt;span style="color:#f92672">=&lt;/span> t&lt;span style="color:#f92672">.&lt;/span>shape[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> out &lt;span style="color:#f92672">=&lt;/span> a&lt;span style="color:#f92672">.&lt;/span>gather(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>,t) &lt;span style="color:#75715e"># (B,)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> out&lt;span style="color:#f92672">.&lt;/span>view(batch_size, &lt;span style="color:#f92672">*&lt;/span>((&lt;span style="color:#ae81ff">1&lt;/span>,) &lt;span style="color:#f92672">*&lt;/span> (len(x_shape) &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>))) &lt;span style="color:#75715e"># (B,1,1,1...)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">MLP&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 这是一个简单的多层感知机(MLP)模型，结合了时间步的位置编码，用于处理状态和动作的输入（强化学习）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self,state_dim,action_dim,hidden_dim,device,t_dim):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super(MLP,self)&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>device &lt;span style="color:#f92672">=&lt;/span> device
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>t_dim &lt;span style="color:#f92672">=&lt;/span> t_dim
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>a_tim &lt;span style="color:#f92672">=&lt;/span> action_dim
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>time_mlp &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Sequential(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> SinusoidalPosEmb(t_dim),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(t_dim,t_dim&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Mish(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(t_dim&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>,t_dim)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input_dim &lt;span style="color:#f92672">=&lt;/span> state_dim &lt;span style="color:#f92672">+&lt;/span> action_dim &lt;span style="color:#f92672">+&lt;/span> t_dim
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>mid_layer &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Sequential(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(input_dim,hidden_dim),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Mish(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(hidden_dim,hidden_dim),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Mish(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(hidden_dim,hidden_dim),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>Mish(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>f_layer &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(hidden_dim,action_dim)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">init_weights&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 初始化模型权重,好的权重初始化可以帮助模型更快收敛，提升训练效果。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> m &lt;span style="color:#f92672">in&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>modules():
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> isinstance(m,nn&lt;span style="color:#f92672">.&lt;/span>Linear):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>init&lt;span style="color:#f92672">.&lt;/span>xavier_normal_(m&lt;span style="color:#f92672">.&lt;/span>weight)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> m&lt;span style="color:#f92672">.&lt;/span>bias &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> nn&lt;span style="color:#f92672">.&lt;/span>init&lt;span style="color:#f92672">.&lt;/span>zeros_(m&lt;span style="color:#f92672">.&lt;/span>bias)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,state,action,t):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t_emb &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>time_mlp(t) &lt;span style="color:#75715e"># (batch,t_dim)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cat((state,action,t_emb),dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#75715e"># (batch,state_dim+action_dim+t_dim)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>mid_layer(x) &lt;span style="color:#75715e"># (batch,hidden_dim)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> action_delta &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>f_layer(x) &lt;span style="color:#75715e"># (batch,action_dim)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> action_delta
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Diffusion&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self,loss_type,beta_schedule&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;linear&amp;#39;&lt;/span>,clip_denoise&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>,predict_epsilon&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>,&lt;span style="color:#f92672">**&lt;/span>kwargs):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> loss_type: 损失函数类型
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> beta_schedule: beta(时间)的离散方式，常见的有&amp;#39;linear&amp;#39;（线性）和&amp;#39;cosine&amp;#39;（余弦）。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> clip_denoise: 是否在去噪过程中裁剪输出，以防止数值过大。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super(Diffusion,self)&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>device &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;device&amp;#39;&lt;/span>,&lt;span style="color:#e6db74">&amp;#39;cpu&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>t_dim &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;t_dim&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">16&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>state_dim &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;state_dim&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">10&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>action_dim &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;action_dim&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>hidden_dim &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;hidden_dim&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">256&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>loss_type &lt;span style="color:#f92672">=&lt;/span> loss_type
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>beta_schedule &lt;span style="color:#f92672">=&lt;/span> beta_schedule
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>clip_denoise &lt;span style="color:#f92672">=&lt;/span> clip_denoise
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>T &lt;span style="color:#f92672">=&lt;/span> kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;timesteps&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">1000&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model &lt;span style="color:#f92672">=&lt;/span> MLP(self&lt;span style="color:#f92672">.&lt;/span>state_dim,self&lt;span style="color:#f92672">.&lt;/span>action_dim,self&lt;span style="color:#f92672">.&lt;/span>hidden_dim,self&lt;span style="color:#f92672">.&lt;/span>device,self&lt;span style="color:#f92672">.&lt;/span>t_dim)&lt;span style="color:#f92672">.&lt;/span>to(self&lt;span style="color:#f92672">.&lt;/span>device)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>kwargs &lt;span style="color:#f92672">=&lt;/span> kwargs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>model&lt;span style="color:#f92672">.&lt;/span>init_weights()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> beta_schedule &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;linear&amp;#39;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> betas &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>linspace(&lt;span style="color:#ae81ff">1e-4&lt;/span>,&lt;span style="color:#ae81ff">0.02&lt;/span>,self&lt;span style="color:#f92672">.&lt;/span>kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;timesteps&amp;#39;&lt;/span>, &lt;span style="color:#ae81ff">1000&lt;/span>),dtype&lt;span style="color:#f92672">=&lt;/span>torch&lt;span style="color:#f92672">.&lt;/span>float32)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> alphas &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> betas
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> alphas_cumprod &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cumprod(alphas,dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>) &lt;span style="color:#75715e"># [1,2,3] -&amp;gt; [1,1*2,1*2*3]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> alphas_cumprod_prev &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cat((torch&lt;span style="color:#f92672">.&lt;/span>tensor([&lt;span style="color:#ae81ff">1.&lt;/span>],dtype&lt;span style="color:#f92672">=&lt;/span>torch&lt;span style="color:#f92672">.&lt;/span>float32),alphas_cumprod[:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]),dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;betas&amp;#39;&lt;/span>,betas)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;alphas&amp;#39;&lt;/span>,alphas)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;alphas_cumprod&amp;#39;&lt;/span>,alphas_cumprod)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;alphas_cumprod_prev&amp;#39;&lt;/span>,alphas_cumprod_prev)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;sqrt_alphas_cumprod&amp;#39;&lt;/span>,torch&lt;span style="color:#f92672">.&lt;/span>sqrt(alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># （前向过程）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;sqrt_alphas_cumprob&amp;#39;&lt;/span>,torch&lt;span style="color:#f92672">.&lt;/span>sqrt(alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;sqrt_one_minus_alphas_cumprod&amp;#39;&lt;/span>,torch&lt;span style="color:#f92672">.&lt;/span>sqrt(&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># （反向过程）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> posterior_variance &lt;span style="color:#f92672">=&lt;/span> betas &lt;span style="color:#f92672">*&lt;/span> (&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod_prev) &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;posterior_variance&amp;#39;&lt;/span>,posterior_variance)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 用于从xt求得x0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;sqrt_recip_alphas_cumprod&amp;#39;&lt;/span>,torch&lt;span style="color:#f92672">.&lt;/span>sqrt(&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">/&lt;/span> alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;sqrt_recipm1_alphas_cumprod&amp;#39;&lt;/span>,torch&lt;span style="color:#f92672">.&lt;/span>sqrt(&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">/&lt;/span> alphas_cumprod &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;posterior_mean_coef1&amp;#39;&lt;/span>,betas &lt;span style="color:#f92672">*&lt;/span>torch&lt;span style="color:#f92672">.&lt;/span>sqrt(alphas_cumprod_prev) &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>register_buffer(&lt;span style="color:#e6db74">&amp;#39;posterior_mean_coef2&amp;#39;&lt;/span>, (&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod_prev) &lt;span style="color:#f92672">*&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>sqrt(alphas) &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#ae81ff">1.&lt;/span> &lt;span style="color:#f92672">-&lt;/span> alphas_cumprod))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>loss_func &lt;span style="color:#f92672">=&lt;/span> Losses[loss_type]()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,state,&lt;span style="color:#f92672">*&lt;/span>args,&lt;span style="color:#f92672">**&lt;/span>kwargs):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>sample(state,&lt;span style="color:#f92672">*&lt;/span>args,&lt;span style="color:#f92672">**&lt;/span>kwargs)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">sample&lt;/span>(self,state,&lt;span style="color:#f92672">*&lt;/span>args,&lt;span style="color:#f92672">**&lt;/span>kwargs):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_size &lt;span style="color:#f92672">=&lt;/span> state&lt;span style="color:#f92672">.&lt;/span>shape[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> shape &lt;span style="color:#f92672">=&lt;/span> [batch_size,self&lt;span style="color:#f92672">.&lt;/span>action_dim]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> action &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>p_sample_loop(state,shape,&lt;span style="color:#f92672">*&lt;/span>args,&lt;span style="color:#f92672">**&lt;/span>kwargs)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> action&lt;span style="color:#f92672">.&lt;/span>clamp(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1.&lt;/span>,&lt;span style="color:#ae81ff">1.&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">q_posterior&lt;/span>(self,x0,xt,t):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 计算后验分布q(x_{t-1}|x_t,x_0)的均值和方差
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> posterior_mean &lt;span style="color:#f92672">=&lt;/span> (extract(self&lt;span style="color:#f92672">.&lt;/span>posterior_mean_coef1,t,x0&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> x0 &lt;span style="color:#f92672">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> extract(self&lt;span style="color:#f92672">.&lt;/span>posterior_mean_coef2,t,x0&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> xt)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> posterior_variance &lt;span style="color:#f92672">=&lt;/span> extract(self&lt;span style="color:#f92672">.&lt;/span>posterior_variance,t,x0&lt;span style="color:#f92672">.&lt;/span>shape)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> posterior_log_variance &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>log(posterior_variance&lt;span style="color:#f92672">.&lt;/span>clamp(min&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1e-20&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> posterior_mean,posterior_variance,posterior_log_variance
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p_sample_loop&lt;/span>(self,state,shape,&lt;span style="color:#f92672">*&lt;/span>args,&lt;span style="color:#f92672">**&lt;/span>kwargs):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> device &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;device&amp;#39;&lt;/span>,&lt;span style="color:#e6db74">&amp;#39;cpu&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_size &lt;span style="color:#f92672">=&lt;/span> shape[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn(shape,device&lt;span style="color:#f92672">=&lt;/span>device,requires_grad&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">False&lt;/span>) &lt;span style="color:#75715e"># 标准DDPM噪声不需要梯度&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> reversed(range(&lt;span style="color:#ae81ff">0&lt;/span>,self&lt;span style="color:#f92672">.&lt;/span>kwargs&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;timesteps&amp;#39;&lt;/span>,&lt;span style="color:#ae81ff">1000&lt;/span>))):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>full((batch_size,),i,dtype&lt;span style="color:#f92672">=&lt;/span>torch&lt;span style="color:#f92672">.&lt;/span>long,device&lt;span style="color:#f92672">=&lt;/span>device)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>p_sample(x,t,state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> x
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">predict_x0_from_noise&lt;/span>(self,x,t,noise):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> 根据公式计算x0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (extract(self&lt;span style="color:#f92672">.&lt;/span>sqrt_recip_alphas_cumprod,t,x&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> x &lt;span style="color:#f92672">-&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> extract(self&lt;span style="color:#f92672">.&lt;/span>sqrt_recipm1_alphas_cumprod,t,x&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> noise)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p_mean_variance&lt;/span>(self,x,t,state):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> pred_noise &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model(state,x,t)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x_0 &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>predict_x0_from_noise(x,t,pred_noise)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x_0&lt;span style="color:#f92672">.&lt;/span>clamp_(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1.&lt;/span>,&lt;span style="color:#ae81ff">1.&lt;/span>) &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>clip_denoise &lt;span style="color:#66d9ef">else&lt;/span> x_0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model_mean,posterior_variance,posterior_log_variance &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>q_posterior(x_0,x,t)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> model_mean,posterior_log_variance
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p_sample&lt;/span>(self,x,t,state):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> x: 当前的噪声状态xt
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> t: 当前的时间步t
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> state: 状态
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model_mean,model_log_variance &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>p_mean_variance(x,t,state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> noise &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn_like(x) &lt;span style="color:#66d9ef">if&lt;/span> t&lt;span style="color:#f92672">.&lt;/span>sum() &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#ae81ff">0.&lt;/span> &lt;span style="color:#75715e"># 如果t=0,则不添加噪声&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> model_mean &lt;span style="color:#f92672">+&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>exp(&lt;span style="color:#ae81ff">0.5&lt;/span> &lt;span style="color:#f92672">*&lt;/span> model_log_variance) &lt;span style="color:#f92672">*&lt;/span> noise
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">q_sample&lt;/span>(self,x0,t,noise):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sample &lt;span style="color:#f92672">=&lt;/span> (extract(self&lt;span style="color:#f92672">.&lt;/span>sqrt_alphas_cumprod,t,x0&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> x0 &lt;span style="color:#f92672">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> extract(self&lt;span style="color:#f92672">.&lt;/span>sqrt_one_minus_alphas_cumprod,t,x0&lt;span style="color:#f92672">.&lt;/span>shape) &lt;span style="color:#f92672">*&lt;/span> noise)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> sample
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p_losses&lt;/span>(self,x0,state,t,weights):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> noise &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn_like(x0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x_noisy &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>q_sample(x0,t,noise)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x_recon &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>model(state,x_noisy,t)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loss &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>loss_func(x_recon,noise,weights)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> loss
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">loss&lt;/span>(self,x,state,weights&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1.0&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_size &lt;span style="color:#f92672">=&lt;/span> x&lt;span style="color:#f92672">.&lt;/span>shape[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> t &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randint(&lt;span style="color:#ae81ff">0&lt;/span>,self&lt;span style="color:#f92672">.&lt;/span>T,(batch_size,),device&lt;span style="color:#f92672">=&lt;/span>self&lt;span style="color:#f92672">.&lt;/span>device)&lt;span style="color:#f92672">.&lt;/span>long()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>p_losses(x,state,t,weights)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> __name__ &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;__main__&amp;#39;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn(&lt;span style="color:#ae81ff">256&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> state &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn(&lt;span style="color:#ae81ff">256&lt;/span>,&lt;span style="color:#ae81ff">11&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model &lt;span style="color:#f92672">=&lt;/span> Diffusion(loss_type&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;l2&amp;#39;&lt;/span>,beta_schedule&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;linear&amp;#39;&lt;/span>,clip_denoise&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>,predict_epsilon&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> device&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;cpu&amp;#39;&lt;/span>,t_dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>,state_dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">11&lt;/span>,action_dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>,hidden_dim&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">256&lt;/span>,timesteps&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">100&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> result &lt;span style="color:#f92672">=&lt;/span> model(state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(result)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loss &lt;span style="color:#f92672">=&lt;/span> model&lt;span style="color:#f92672">.&lt;/span>loss(x,state)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;loss: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>loss&lt;span style="color:#f92672">.&lt;/span>item()&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>CodeByMySelf-RL</title><link>https://ganko.asia/posts/codebymyself-rl/</link><pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/codebymyself-rl/</guid><description>&lt;blockquote>
&lt;p>所有之前：CodeByMySelf 系列之 RL（深度强化学习）的实现记录，只有标题没有内容的是TODO。&lt;/p>&lt;/blockquote>
&lt;h2 id="rl强化学习深度强化学习">RL强化学习（深度强化学习）&lt;/h2>
&lt;blockquote>
&lt;p>TODO&lt;/p>&lt;/blockquote></description></item><item><title>CodeByMySelf-Transformer</title><link>https://ganko.asia/posts/codebymyself-transformer/</link><pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/codebymyself-transformer/</guid><description>&lt;blockquote>
&lt;p>所有之前：CodeByMySelf 系列之 Transformer 的实现记录，只有标题没有内容的是TODO，针对经典算法的变体和改进算法在其他文章。&lt;/p>&lt;/blockquote>
&lt;h2 id="transformer">Transformer&lt;/h2>
&lt;p>下面是一个最基本的Transformer实现，主要包含以下几个部分：&lt;/p>
&lt;ul>
&lt;li>基本模块
&lt;ul>
&lt;li>多头注意力模块&lt;/li>
&lt;li>Token和位置嵌入模块&lt;/li>
&lt;li>LayerNorm&lt;/li>
&lt;li>前馈神经网络FFN&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>$EncoderLayer -> Encoder$&lt;/li>
&lt;li>$DecoderLayer -> Decoder$&lt;/li>
&lt;li>$Encoder+Decoder -> Transformer$&lt;/li>
&lt;/ul>
&lt;h3 id="多头注意力mha">多头注意力MHA&lt;/h3>
&lt;p>多头注意力机制的公式如下：
&lt;/p>
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)W^O $$&lt;p>其中，每一个头的计算分别为：
&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V $$&lt;p>对于图像数据和序列数据，多头注意力机制的实现是不同，但是核心原理是相同的。对于序列数据，每个位置对应一个token；对于图像数据，每个位置对应一个patch块或者一个像素块，如果是$patch$块，需要展开到一维向量。这里实现的为序列数据的多头注意力机制,初始$shape$为$(batch,time,d_model)$&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> torch &lt;span style="color:#f92672">import&lt;/span> nn
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch.functional &lt;span style="color:#66d9ef">as&lt;/span> F
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> math
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">MultiHeadAttention&lt;/span>(nn&lt;span style="color:#f92672">.&lt;/span>Module):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> __init__(self,d_model,n_head):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> super(MultiHeadAttention, self)&lt;span style="color:#f92672">.&lt;/span>__init__()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">assert&lt;/span> d_model &lt;span style="color:#f92672">%&lt;/span> n_head &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>d_model &lt;span style="color:#f92672">=&lt;/span> d_model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>n_head &lt;span style="color:#f92672">=&lt;/span> n_head
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_k &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model,d_model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_q &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model,d_model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_v &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model,d_model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>w_conbine &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Linear(d_model,d_model,bias&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">False&lt;/span>) &lt;span style="color:#75715e"># 对应W^O&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>softmax &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>Softmax(dim&lt;span style="color:#f92672">=-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">forward&lt;/span>(self,q,k,v,mask&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">None&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch,time,dimension &lt;span style="color:#f92672">=&lt;/span> q&lt;span style="color:#f92672">.&lt;/span>shape() &lt;span style="color:#75715e"># q,k,v shape: (batch,time,d_model)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> n_d &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>d_model &lt;span style="color:#f92672">//&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>n_head
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> q,k,v &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>w_q(q),self&lt;span style="color:#f92672">.&lt;/span>w_k(k),self&lt;span style="color:#f92672">.&lt;/span>w_v(v)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(q&lt;span style="color:#f92672">.&lt;/span>shape, batch, time, self&lt;span style="color:#f92672">.&lt;/span>n_head, n_d)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> q &lt;span style="color:#f92672">=&lt;/span> q&lt;span style="color:#f92672">.&lt;/span>view(batch,time,self&lt;span style="color:#f92672">.&lt;/span>n_head,n_d)&lt;span style="color:#f92672">.&lt;/span>transpose(&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#75715e"># self.n_head * n_d = d_model&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> k &lt;span style="color:#f92672">=&lt;/span> k&lt;span style="color:#f92672">.&lt;/span>view(batch,time,self&lt;span style="color:#f92672">.&lt;/span>n_head,n_d)&lt;span style="color:#f92672">.&lt;/span>transpose(&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>) &lt;span style="color:#75715e"># shape: (batch,n_head,time,n_d)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> v &lt;span style="color:#f92672">=&lt;/span> v&lt;span style="color:#f92672">.&lt;/span>view(batch,time,self&lt;span style="color:#f92672">.&lt;/span>n_head,n_d)&lt;span style="color:#f92672">.&lt;/span>transpose(&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># compute attention by the formula&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> score &lt;span style="color:#f92672">=&lt;/span> q &lt;span style="color:#f92672">@&lt;/span> k&lt;span style="color:#f92672">.&lt;/span>transpose(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>,&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">/&lt;/span> math&lt;span style="color:#f92672">.&lt;/span>sqrt(n_d) &lt;span style="color:#75715e"># (batch,n_head,time,time)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> mask &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> score &lt;span style="color:#f92672">=&lt;/span> score&lt;span style="color:#f92672">.&lt;/span>masked_fill(mask&lt;span style="color:#f92672">==&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>,float(&lt;span style="color:#e6db74">&amp;#39;-inf&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> attn &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>softmax(score) &lt;span style="color:#f92672">@&lt;/span> v &lt;span style="color:#75715e"># (batch,n_head,time,n_d)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> attn &lt;span style="color:#f92672">=&lt;/span> attn&lt;span style="color:#f92672">.&lt;/span>transpose(&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">2&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>contiguous()&lt;span style="color:#f92672">.&lt;/span>view(batch,time,dimension) &lt;span style="color:#75715e"># (batch,time,dimension)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> attn &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>w_conbine(attn) &lt;span style="color:#75715e"># (batch,time,dimension)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> attn
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>d_model &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">512&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>n_head &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mha &lt;span style="color:#f92672">=&lt;/span> MultiHeadAttention(d_model,n_head)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>x &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>randn(&lt;span style="color:#ae81ff">2&lt;/span>,&lt;span style="color:#ae81ff">10&lt;/span>,d_model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>y &lt;span style="color:#f92672">=&lt;/span> mha(x,x,x) &lt;span style="color:#75715e"># self-multi-head-attention&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;shape: &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>y&lt;span style="color:#f92672">.&lt;/span>shape&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">输出:&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>y&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>) &lt;span style="color:#75715e"># torch.Size([2, 10, 512])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="token和位置嵌入模块">Token和位置嵌入模块&lt;/h3>
&lt;p>Token Embedding 是将离散的词（token）转换为连续的向量表示的过程。通常通过查找表（如 nn.Embedding）将每个词的索引映射为一个高维向量，使模型能够处理和学习词之间的语义关系。
公式表示： &lt;/p></description></item><item><title>CodeByMySelf-VAE</title><link>https://ganko.asia/posts/codebymyself-vae/</link><pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/codebymyself-vae/</guid><description>&lt;blockquote>
&lt;p>所有之前：CodeByMySelf 系列之 VAE（变分自编码器）的实现记录，只有标题没有内容的是TODO。&lt;/p>&lt;/blockquote>
&lt;h2 id="vae变分自编码器">VAE（变分自编码器）&lt;/h2>
&lt;p>VAE也是一个非常经典的生成模型，虽然现在主流已经是Diffusion模型，但是它的原理和思想还是非常有启发性的，尤其是对于理解diffusion中的一些概念（如潜在空间、重参数化技巧等）非常有帮助。&lt;/p>
&lt;blockquote>
&lt;p>TODO&lt;/p>&lt;/blockquote></description></item><item><title>并行训练实践</title><link>https://ganko.asia/posts/%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E5%AE%9E%E8%B7%B5/</link><pubDate>Thu, 24 Jul 2025 00:00:00 +0000</pubDate><guid>https://ganko.asia/posts/%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E5%AE%9E%E8%B7%B5/</guid><description>&lt;h2 id="accelerate">Accelerate&lt;/h2>
&lt;p>Accelerate 是 Hugging Face 开发的深度学习多卡并行训练库，构建在 &lt;code>torch_xla&lt;/code> 和 &lt;code>torch.distributed&lt;/code> 之上。它提供了一个简单的 API，将与多 GPU、TPU、混合精度训练相关的样板代码抽离了出来，让用户可以在不同设备上轻松地进行分布式训练和混合精度训练，而无需重复编写大量样板代码。&lt;/p>
&lt;p>另外，Accelerate 还提供了很多性能优化的功能，使得大规模训练和推理变得简单、高效且适应性强。&lt;/p>
&lt;p>在学习如何使用 Accelerate 之前，首先回顾一下并行训练的其他方法。&lt;/p>
&lt;hr>
&lt;h2 id="dataparallel-dp">DataParallel (DP)&lt;/h2>
&lt;p>DP 是最常见的并行训练方式，通过将数据拆分（split）到各个 workers 中（每个 worker 拥有完整模型）进行并行计算，以解决 Batch Size 过大的问题。因为求导以及加和都是线性的，所以数据并行在数学上是等价的。&lt;/p>
&lt;p>&lt;code>DataParallel&lt;/code> 是 PyTorch 中最容易实现的并行方案，只需要增加一行代码：&lt;code>model = nn.DataParallel(model)&lt;/code>。&lt;/p>
&lt;h3 id="代码示例">代码示例&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> torch.nn &lt;span style="color:#66d9ef">as&lt;/span> nn
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> torch.utils.data &lt;span style="color:#f92672">import&lt;/span> DataLoader, Dataset
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 数据集的长度为 100，batch size 为 32&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 模型是一个简单的 fc 层，输入长度是 5，输出是 2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>input_size, output_size &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>batch_size, data_size &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span>, &lt;span style="color:#ae81ff">100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>model &lt;span style="color:#f92672">=&lt;/span> Model(input_size, output_size)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>device_count() &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Detected &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>device_count()&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> GPUs!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model &lt;span style="color:#f92672">=&lt;/span> nn&lt;span style="color:#f92672">.&lt;/span>DataParallel(model)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>device &lt;span style="color:#f92672">=&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>device(&lt;span style="color:#e6db74">&amp;#34;cuda:0&amp;#34;&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> torch&lt;span style="color:#f92672">.&lt;/span>cuda&lt;span style="color:#f92672">.&lt;/span>is_available() &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#e6db74">&amp;#34;cpu&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>model&lt;span style="color:#f92672">.&lt;/span>to(device)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rand_loader &lt;span style="color:#f92672">=&lt;/span> DataLoader(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dataset&lt;span style="color:#f92672">=&lt;/span>RandomDataset(input_size, data_size),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> batch_size&lt;span style="color:#f92672">=&lt;/span>batch_size,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> shuffle&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> data &lt;span style="color:#f92672">in&lt;/span> rand_loader:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> input &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>to(device)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> output &lt;span style="color:#f92672">=&lt;/span> model(input)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在上述代码中，&lt;code>batch_size=32&lt;/code>。由于使用了 &lt;code>DataParallel&lt;/code>，在有 2 个 GPU 时，一个 batch 被划分成了 2 份，即 &lt;code>tensor.split(16)&lt;/code>，分别送往两个 GPU。&lt;/p></description></item></channel></rss>