<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Machine Learning System | Shaopu Song</title><link>https://shaopu.tech/tag/machine-learning-system/</link><atom:link href="https://shaopu.tech/tag/machine-learning-system/index.xml" rel="self" type="application/rss+xml"/><description>Machine Learning System</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><lastBuildDate>Thu, 25 Jun 2026 00:00:00 +0000</lastBuildDate><item><title>CS 336</title><link>https://shaopu.tech/post/cs-336/</link><pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate><guid>https://shaopu.tech/post/cs-336/</guid><description>&lt;h2 id="basics">Basics&lt;/h2>
&lt;ul>
&lt;li>资源量的计算：两个方面：memory &amp;amp; compute&lt;/li>
&lt;/ul>
&lt;p>total_flops公式：$6 \times token_num \times param_num$ (对每一个输入的token ，前向要跑过所有的参数，每一个参数都要参与矩阵乘，每个元素都需要经过一次加法和乘法，所以前向需要2TP，反向需要对输出和权重各做一次相同的操作，所以一共需要6TP)&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-27-045537.png" alt="image-20260627125537371" style="zoom:50%;" />
&lt;ul>
&lt;li>Scaling Law的建立：用小模型拟合出scale分布曲线（scaling recipe），要求建立比较细致的recipe，包括BS改变的影响等；这是因为一次大规模资源量消耗太大，不可能不断通过大型实验来发现最佳超参；&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-27-113316.png" alt="image-20260627193316207" style="zoom:50%;" />
&lt;h2 id="tokenization">Tokenization&lt;/h2>
&lt;p>Encode &amp;lt;-&amp;gt; Decode&lt;/p>
&lt;ul>
&lt;li>
&lt;p>可以通过增大词表(vocab size)的方法，来提高压缩比（string -&amp;gt; indices）；（因为每个token可以表示的信息可能会变得更多），这会导致：&lt;/p>
&lt;p>A. 序列长度更短（对attention友好）&lt;/p>
&lt;p>B. sparsity增大，因为有很多embedding可能都不会被学到，这不是好事&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="bpe_tokenizer">BPE_tokenizer&lt;/h3>
&lt;p>&lt;strong>思路&lt;/strong>：在原始数据上训练tokenizer，得到一个贴合数据的vocabulary；最终让常见的序列可以用一个token来表示，不常见的序列用很多个token来表示；&lt;/p>
&lt;p>&lt;strong>方法&lt;/strong>：一开始将每个byte当作一个token，之后不断merge常见的相邻的tokens。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">merge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">tuple&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">new_index&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Return `indices`, but with all instances of `pair` replaced with `new_index`.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_indices&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_indices&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_index&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_indices&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">new_indices&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">BPETokenizerParams&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;All you need to specify a BPETokenizer.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vocab&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">bytes&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># index -&amp;gt; bytes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">merges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">tuple&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># index1,index2 -&amp;gt; new_index&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">train_bpe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num_merges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">BPETokenizerParams&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Start&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="nb">list&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="nb">bytes&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">merges&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">tuple&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span> &lt;span class="c1"># index1, index2 =&amp;gt; merged index&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vocab&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">bytes&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bytes&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">256&lt;/span>&lt;span class="p">)}&lt;/span> &lt;span class="c1"># index -&amp;gt; bytes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num_merges&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Count the number of occurrences of each pair of tokens&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">count_adjacent_pairs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Find the most common pair&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pair&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">counts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Merge that pair&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_index&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">merges&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">pair&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">new_index&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vocab&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">new_index&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vocab&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">pair&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">vocab&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">pair&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">merge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_index&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">compression_ratio&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_compression_ratio&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">BPETokenizerParams&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">merges&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">merges&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">count_adjacent_pairs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">tuple&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Return a dictionary mapping each adjacent pair of tokens in `indices` to the number of times it occurs.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">defaultdict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">index1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">index2&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">zip&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">:]):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counts&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">index1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">index2&lt;/span>&lt;span class="p">)]&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">counts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">BPETokenizer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Tokenizer&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;BPE tokenizer given a set of merges and a vocabulary.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">BPETokenizerParams&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">params&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">encode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">encode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Note: this is a very slow implementation&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_index&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merges&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">merge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pair&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_index&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">indices&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bytes_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vocab&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indices&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bytes_list&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">string&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="resource-accounting">Resource Accounting&lt;/h2>
&lt;h3 id="einops">Einops&lt;/h3>
&lt;ul>
&lt;li>motivation: 因为使用普通的pytorch矩阵行列变换操作很容易出错，einops方便我们对dimension进行操作；&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ones&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ones&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- sum ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">@&lt;/span> &lt;span class="n">y&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 等价于&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">einsum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;seq1 hidden, hidden seq2 -&amp;gt; seq1 seq2&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">@&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">transpose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 等价于 (或者手动将...写成&amp;#39;batch&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">einsum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;... seq1 hidden, ... seq2 hidden -&amp;gt; ... seq1 seq2&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- reduce ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dim&lt;/span>&lt;span class="o">=-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 等价于&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">reduce&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;...hidden -&amp;gt; ...&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;sum&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># --- rearrange ---&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (3, 8) -&amp;gt; (3, 2, 4)，或者反过来也可以&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">rearrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;...(heads hidden1) -&amp;gt; ... heads hidden1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">heads&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="flops-of-matmul-operation">Flops of matmul operation&lt;/h3>
&lt;p>x: (B, D), w: (D, K) 每个位置包含一次加法和乘法，故flops为$2*BDK$&lt;/p>
&lt;ul>
&lt;li>B是点的数量&lt;/li>
&lt;li>(DK)是参数的数量&lt;/li>
&lt;/ul>
&lt;p>那么对于一次前向的矩阵乘法，flops就是$2*tokens*params$，也是前边整体flops计算公式的由来。&lt;/p>
&lt;h3 id="mfu">MFU&lt;/h3>
&lt;p>MFU: Model FlOPS Utilization = actual flop_per_second / promised flop_per_second&lt;/p>
&lt;blockquote>
&lt;p>promised flop per second: 可以在设备指标中找到&lt;/p>
&lt;/blockquote>
&lt;p>一般大于等于0.5的MFU就算是很好了.&lt;/p>
&lt;h4 id="arithmetic-intensity">arithmetic intensity&lt;/h4>
&lt;p>两个组件：计算单元&amp;amp; memory，所以计算耗时取决于两个因素：&lt;/p>
&lt;ol>
&lt;li>Accelerator speed (FLOP/s)&lt;/li>
&lt;li>memory bandwith (bytes/s)&lt;/li>
&lt;/ol>
&lt;p>衡量程序是compute boundh还是memory bound有两种方法：&lt;/p>
&lt;p>首先可以比较communication time和compute time：&lt;/p>
&lt;ul>
&lt;li>communication time: bytes / h100_bytes_per_second&lt;/li>
&lt;li>compute time: flops / h100_flop_per_second&lt;/li>
&lt;/ul>
&lt;p>我们假设通信和计算可以overlap，那么：&lt;/p>
&lt;ul>
&lt;li>memory bound: communication time &amp;gt; compute time&lt;/li>
&lt;li>compute bound: compute time &amp;gt; communication time&lt;/li>
&lt;/ul>
&lt;p>另一种等价的衡量方式：&lt;/p>
&lt;ul>
&lt;li>Accelarator intensity: h100_flop_per_second / h100_bytes_per_second&lt;/li>
&lt;li>Arithmetic intensity: flops / bytes&lt;/li>
&lt;/ul>
&lt;p>那么：&lt;/p>
&lt;ul>
&lt;li>memory bound: Accelerator intensity &amp;gt; arithmetic intensity&lt;/li>
&lt;li>compute bound: Arithmetic intensity &amp;gt; accelerator intensity&lt;/li>
&lt;/ul>
&lt;h5 id="example-matmul">example: matmul&lt;/h5>
&lt;p>bytes: 2nn+2nn+2nn&lt;/p>
&lt;p>Flops: nn(2n-1)&lt;/p>
&lt;p>只要matrix足够大，就是一个compute bound的操作。&lt;/p>
&lt;blockquote>
&lt;p>为什么推理过程是memory bound的？因为推理大多做的是matrix-vector multiplication.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1024&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ones&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">device&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">cuda_if_available&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">w&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ones&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">device&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">cuda_if_available&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">@&lt;/span> &lt;span class="n">w&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">bytes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Read x, read w, write y&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">flops&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># n dot-products&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">arithmetic_intensity&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">flops&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="nb">bytes&lt;/span> &lt;span class="c1"># ~1 &lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>H100_accelerator_intensity &amp;raquo; arithmetic intensity&lt;/p>
&lt;/blockquote>
&lt;h4 id="roofline-plots">roofline plots&lt;/h4>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-142651.png" alt="image-20260630171554556" style="zoom:50%;" />
&lt;p>在前期，如果搬运每个byte所对应的计算操作很少，那么显然大部分资源都被浪费在memory上，而非计算单元内。&lt;/p>
&lt;h2 id="architecture">Architecture&lt;/h2>
&lt;h3 id="layernorm">Layernorm&lt;/h3>
&lt;h4 id="pre-vs-post-norm">Pre-vs-post norm&lt;/h4>
&lt;p>将$x_i$-&amp;gt;$x_{i+1}$的通路称为residual stream，目前主流的方法是右侧的pre-norm，即在mha和FFN之前做layer norm. 因为不在residual stream上，所以也被称为non-residual norm.&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-144243.png" alt="image-20260630224243612" style="zoom: 50%;" />
&lt;p>优势：&lt;/p>
&lt;ul>
&lt;li>即使不经过warmup，也可以有相比post-norm更好的稳定性，更少的gradient spike现象。&lt;/li>
&lt;/ul>
&lt;p>现在还有一种方法是在计算之后也加上layernorm：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-144922.png" alt="image-20260630224921419" style="zoom:50%;" />
&lt;p>也被叫做double norm.&lt;/p>
&lt;h4 id="layernorm-vs-rmsnorm">Layernorm vs. RMSNorm&lt;/h4>
&lt;p>观察这两者的公式区别：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-151120.png" alt="image-20260630231120523" style="zoom:50%;" />
&lt;p>RMSNorm相比layernorm，有着更少的操作（不需要计算mean）和更少的参数（没后bias term），事实上这两个diff对性能的提升至关重要：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-151325.png" alt="image-20260630231325814" style="zoom:50%;" />
&lt;p>可以看到虽然normalization和element-wise的bias term计算的flop很少，但是占用的时间却很长。&lt;/p>
&lt;blockquote>
&lt;p>在现代的LLM transformer架构中，bias term也经常是没有的.&lt;/p>
&lt;/blockquote>
&lt;h3 id="activations">Activations&lt;/h3>
&lt;p>一个architecture设计的经验之谈：gating往往很有帮助；其实就是一个矩阵乘法。&lt;/p>
&lt;p>比如在activation的设计中，从relu到**GLU的演化就是多了一个gate function:&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-155855.png" alt="image-20260630235855229" style="zoom:50%;" />
&lt;p>各种GLU的不同就在于新增加的参数矩阵V的选择的不同，对于目前最通用的SwiGLU，选择的是一个$sigmoid(x)$:&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-155954.png" alt="image-20260630235954155" style="zoom:50%;" />
&lt;p>这里的一个小细节是为了让总参数量和之前一样（因为增加了一个新的权重矩阵v），对dim需要进行缩减。&lt;/p>
&lt;h3 id="serial-vs-parallel-layers">Serial vs. Parallel layers&lt;/h3>
&lt;p>GPTJ ,PaLM, GPT-NeoX等模型提出了将原本序列化运算的transformer结构改造成parallel的：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-06-30-160636.png" alt="image-20260701000635971" style="zoom:50%;" />
&lt;p>但目前不常用。&lt;/p>
&lt;h3 id="位置编码">位置编码&lt;/h3>
&lt;p>参考资料：&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>&lt;a href="https://kazemnejad.com/blog/transformer_architecture_positional_encoding/" target="_blank" rel="noopener">https://kazemnejad.com/blog/transformer_architecture_positional_encoding/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/721032991" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/721032991&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://spaces.ac.cn/archives/8231" target="_blank" rel="noopener">https://spaces.ac.cn/archives/8231&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/642884818" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/642884818&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mp.weixin.qq.com/s/-1xVXjoM0imXMC7DKqo-Gw" target="_blank" rel="noopener">https://mp.weixin.qq.com/s/-1xVXjoM0imXMC7DKqo-Gw&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kexue.fm/archives/8265/comment-page-2" target="_blank" rel="noopener">https://kexue.fm/archives/8265/comment-page-2&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mp.weixin.qq.com/s?__biz=MzA3MTgwODE1Ng==&amp;amp;mid=2247484826&amp;amp;idx=1&amp;amp;sn=8935f0bcb2e09f438cbf3ae63825d671&amp;amp;chksm=9f26a069a851297f568ba7cd111082e603108716928b8444a253457233f24d09d3a18447d6b9&amp;amp;cur_album_id=3199751010206973953&amp;amp;scene=189#wechat_redirect" target="_blank" rel="noopener">https://mp.weixin.qq.com/s?__biz=MzA3MTgwODE1Ng==&amp;mid=2247484826&amp;idx=1&amp;sn=8935f0bcb2e09f438cbf3ae63825d671&amp;chksm=9f26a069a851297f568ba7cd111082e603108716928b8444a253457233f24d09d3a18447d6b9&amp;cur_album_id=3199751010206973953&amp;scene=189#wechat_redirect&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;ul>
&lt;li>为什么要有位置编码？&lt;/li>
&lt;/ul>
&lt;p>因为attention结构本身无法捕捉token顺序。&lt;/p>
&lt;p>位置编码有以下几个要求：&lt;/p>
&lt;ol>
&lt;li>能够表示一个token在序列中的绝对位置；&lt;/li>
&lt;li>能够用绝对位置表示token间的相对位置；&lt;/li>
&lt;li>具有外推性，即可以表示模型在训练过程中没有见过的长度；&lt;/li>
&lt;/ol>
&lt;h4 id="sinusoidal位置编码">Sinusoidal位置编码&lt;/h4>
&lt;p>正余弦位置编码的思路来自于位置本身的二进制表示，提供了一种有界又连续的编码方法：
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-145206.png" alt="Sinusoidal position encoding" style="zoom:50%;" />&lt;/p>
&lt;ul>
&lt;li>为什么$\omega_k = \frac{1}{10000^{2k / d}}$?&lt;/li>
&lt;/ul>
&lt;p>为了满足设想：相关距离越远的embedding，相关性应该越小；也即远程衰减性：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-145552.png" alt="image-20260703225551965" style="zoom:50%;" />
&lt;ul>
&lt;li>绝对位置编码如何表达相对位置信息？&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-145704.png" alt="image-20260703225703942" style="zoom:50%;" />
&lt;h4 id="rope">ROPE&lt;/h4>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-081015.png" alt="image-20260704161015309" style="zoom:50%;" />
&lt;p>对于二维向量：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-150032.png" alt="image-20260703230032401" style="zoom:50%;" />
&lt;p>即在向量上乘上一个旋转矩阵，同样地对于多偶数维向量，可以将其两两分组(注意这里的$\theta$对每个d的值是不同的)，我们接下来会证明为什么这个形式是可以表达相对位置信息的；&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-150123.jpg" alt="Image" style="zoom:50%;" />
&lt;p>上式中的旋转矩阵十分稀疏，为了节省算力，可以以下面的方式等效实现：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-03-150253.jpg" alt="Image" style="zoom:50%;" />
&lt;p>上述公式里$\theta$的取值可以复用先前正余弦位置编码的方法，同样带来一定的远程衰减性。&lt;/p>
&lt;ul>
&lt;li>ROPE是如何用绝对位置编码表示相对位置信息的？&lt;/li>
&lt;/ul>
&lt;p>我们考察二维下的ROPE，注意到其相当于在embedding上乘了一个旋转矩阵，设旋转矩阵为$R$，那我们尝试证明：&lt;/p>
&lt;p>$$&amp;lt;R_aX,R_bY&amp;gt;=&amp;lt;X,R_{b-a}Y&amp;gt;$$&lt;/p>
&lt;p>注意到旋转矩阵的性质：&lt;/p>
&lt;ol>
&lt;li>$$R_a^T=R_{-a}$$&lt;/li>
&lt;li>$$R_aR_b=R_{a+b}$$&lt;/li>
&lt;/ol>
&lt;p>则：&lt;/p>
&lt;p>$$&amp;lt;R_aX,R_bY&amp;gt;=(R_aX)^TR_bY=X^TR_a^TR_bY=X^TR_{b-a}Y=&amp;lt;X,R_{b-a}Y&amp;gt;$$&lt;/p>
&lt;p>那么对于高维向量，由于内积具有线性性质，即$&amp;lt;a,b&amp;gt;=a_0b_0+a_1b_1+a_2b_2+a_3b_3+&amp;hellip;=&amp;lt;a^0,b^0&amp;gt;+&amp;lt;a^1b^1&amp;gt;+&amp;hellip;$，其中$a^0=[a_0,a_1]$，以此类推；所以将高维向量做两两分组并分别应用旋转矩阵后，上述在二维空间推导出的性质仍然成立。&lt;/p>
&lt;ul>
&lt;li>ROPE为何具有外推性？&lt;/li>
&lt;/ul>
&lt;p>本质上是因为旋转矩阵的存在，让位置编码具备了&lt;strong>周期性&lt;/strong>和&lt;strong>远程衰减性&lt;/strong>，这两个性质允许我们做类似线性插值（将推理时没有见过的旋转角度恢复到训练时见过的角度范围内），以及后续的优化高频信息的NTK插值等方法，通过缩小旋转弧度$m\theta_i$达到长度扩展的目的，具体参见参考文章的最后一篇内容。&lt;/p>
&lt;h3 id="hyperparameters">Hyperparameters&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Feedforward-model dimension ratio&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>对transformer中的FFN层的一般形式：&lt;/p>
&lt;p>$$FFN(x)=max(0,xW_1+b_1)W_2+b_2$$&lt;/p>
&lt;p>一般都有$d_{ff}=4d_{model}$或者$d_ff=2.66d_{model}$.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Head_dim * num_heads to model-dim ratio&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>基本会保持model dim是head dim * num_heads的整数倍，大部分是1:&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-083633.png" alt="image-20260704163633057" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>Aspect ratios&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>表征模型的宽度和深度的比值，主要考量在于如果模型过深，可能需要通过PP来做并行切分，对性能有影响，对效果的影响则并非主要因素。大部分模型的d_model / n_layer都在100左右：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-083801.png" alt="image-20260704163801561" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>vocab sizes&lt;/strong>&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-084129.png" alt="image-20260704164129615" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>Dropout and other regularization&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>在预训练时，因为有很多数据，同时SGD只在语料库上跑一遍，所以想要overfit不太容易，所以有weight decay和dropout的必要吗？大部分现代LLM仍然会做dropout &amp;amp; weight decay，但其目的并非为了防止overfitting，而是在动态优化上（比如和lr decay结合给模型带来的收敛加速）上有优势：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-085857.png" alt="image-20260704165856943" style="zoom:50%;" />
&lt;h3 id="stability-issue">stability issue&lt;/h3>
&lt;h4 id="softmax">Softmax&lt;/h4>
&lt;ul>
&lt;li>&lt;strong>Output softmax stability - z-loss&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>通过增加一个z-loss的正则化项，因为我们在尝试最小化loss，所以这样可以让Z(X)贴近1，从而达到稳定Z(x)的目的.&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-092836.png" alt="image-20260704172835678" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>Attention softmax stability - QK norm&lt;/strong>&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-093201.png" alt="image-20260704173201809" style="zoom:50%;" />
&lt;h4 id="logit-soft-capping">Logit soft-capping&lt;/h4>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-093328.png" alt="image-20260704173328878" style="zoom:50%;" />
&lt;h3 id="attention-heads">Attention heads&lt;/h3>
&lt;p>除了以下几个例外，大部分模型对attention heads都不会有改动：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GQA/MQA (Reduce attention head cost)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-04-180544.png" alt="image-20260705020544527" style="zoom:50%;" />
&lt;p>以上图为例，计算操作的结果源于n&amp;lt;d，所以在projection和attention两个矩阵乘法中，前者占了上风，如果此时的场景换成长文本，即n &amp;raquo; d，那么结果应当为$O(bn^2d)$。&lt;/p>
&lt;p>上述场景发生在训练以及推理的prefill阶段中，但是在decode阶段，假设此时也有N个query token逐次进来：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-05-065501.png" alt="image-20260705145501075" style="zoom:50%;" />
&lt;ul>
&lt;li>arithmetic operations: 仍然是proj占据上风，n次的(b*1*d) @ (d*d)，所以仍然是O(bnd^2);&lt;/li>
&lt;li>total memory access: n次的(b*n*d)还有n次的对proj矩阵(d*d)的访问;&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>这里忽略了softmax的访存，因为比kv读取少一个n的量级，同时因为推理阶段没有backward，所以可以不把softmaxx结果写回HBM.&lt;/p>
&lt;/blockquote>
&lt;p>在decode阶段的计算强度很低，最好需要大batch+短序列，或者模型dim很大，对于小模型不太友好，&lt;/p>
&lt;p>MQA正是为了解决上述痛点。&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-05-075942.png" alt="image-20260705155942416" style="zoom:50%;" />
&lt;p>这里多出的第一项是对Q的读取，先前MHA没有列出来，是因为当时有$bn^2d$的存在。&lt;/p>
&lt;p>但是MQA的问题在于因为head太少，确实会丢失expressiveness (key-query ratio)，所以变成了GQA：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-05-080117.png" alt="image-20260705160117362" style="zoom:50%;" />
&lt;blockquote>
&lt;p>在训练时repeat&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;strong>Sparse / sliding window attention&lt;/strong>&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-05-081147.png" alt="image-20260705161146999" style="zoom:50%;" />
&lt;p>现在比较流行的做法是在full attention和sparse attention之间交替。&lt;/p>
&lt;blockquote>
&lt;p>Long-range info via NoPE, short-range info via RoPE + SWA.&lt;/p>
&lt;/blockquote>
&lt;h2 id="attention-alternatives-and-moe">Attention Alternatives and MOE&lt;/h2>
&lt;h3 id="linear-attention">Linear attention&lt;/h3>
&lt;p>Linear attention的核心思路是思考：如何将(QK^T)V变成Q(K^TV)，其好处在于将O(N^2d_k+N^2d_v)的计算复杂度降低到O(2N*d_v*d_k).&lt;/p>
&lt;p>核心问题在于softmax不是一个满足结合律的操作，即做上述交换之后，效果不等价，所以当前linear attention会使用elu/silu等其他函数，具体细节可以参考网上的其他文章。&lt;/p>
&lt;p>linear attention的优劣明显：&lt;/p>
&lt;ul>
&lt;li>优势：降低计算复杂度，适合推理，原因：可以表示成类似RNN的形式：&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-07-143749.png" alt="image-20260707223748868" style="zoom:50%;" />
&lt;p>因为推理时的token是逐个喂进来的，所以这种串行形式适合推理。&lt;/p>
&lt;ul>
&lt;li>劣势：不适合训练，因为无法并行：由于&lt;em>casual mask&lt;/em>的存在，导致对每个Q token，不能使用一致的K^TV矩阵，必须按照上边展示的那种kv逐次递增的方法来做。&lt;/li>
&lt;/ul>
&lt;p>但是这种方案会有效果问题，所以在实际使用中，例如Minimax M1，使用了hybrid attention的方案，即interleave full attention和linear attention，根据研究表明，两者比值并非线性关系，但有一些证据表明在较低的&lt;code>linear/ratio&lt;/code>比值下，模型效果较好。&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-07-192541.png" alt="image-20260708032540641" style="zoom:50%;" />
&lt;h4 id="lightening-attention">Lightening attention&lt;/h4>
&lt;p>在linear attention的基础上，产生了lightening attention。&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-07-144631.jpg" alt="img" style="zoom:50%;" />
&lt;p>其在linear attention的基础之上，融合了flash attention的想法，即将完整的token序列切成多个block，分段计算attention。&lt;/p>
&lt;p>对于每一个需要依赖先前pos 0-m (属于block1)的pos m+t (属于block2)，从0-m段的attention计算时，缓存中间结果K^TV，并使用linear attention递推到第m位，这样做的好处在于对于长序列场景，前边的所有位置都降低到线性时间复杂度；这在方案中被称为inter block；而对于block2内部的[m+1, m+t)则仍然采用parallel形式的QK^T做计算，充分利用tensor core加速，这在方案中被称为intra block。&lt;/p>
&lt;p>此外，采用了类似FA的cache策略，即做inter_ret + intra_ret的cumsum时，在SRAM中进行等。&lt;/p>
&lt;blockquote>
&lt;p>Future Reading: &lt;a href="https://www.zhihu.com/question/9740764576" target="_blank" rel="noopener">https://www.zhihu.com/question/9740764576&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h4 id="mamba-2">Mamba-2&lt;/h4>
&lt;p>可以理解成在linear attention上加了一个&lt;strong>gating&lt;/strong>：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-07-192142.png" alt="image-20260708032142530" style="zoom:50%;" />
&lt;p>作用是&lt;strong>动态遗忘或保留历史信息，从而更有表达力&lt;/strong>。&lt;/p>
&lt;blockquote>
&lt;p>Nemotron 3使用了该方案.&lt;/p>
&lt;/blockquote>
&lt;h4 id="gated-delta-net">Gated delta net&lt;/h4>
&lt;p>在mamba-2的基础上衍生而来，通过一个投影矩阵$k_tk^T_t$消除历史信息的影响：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-07-192329.png" alt="image-20260708032328809" style="zoom:50%;" />
&lt;p>至于为什么该矩阵是一个&lt;code>project out&lt;/code>的作用，可以参考投影矩阵对应的介绍资料，这里不再赘述。&lt;/p>
&lt;blockquote>
&lt;p>Qwen 3.5 / Qwen Next使用了该方案.&lt;/p>
&lt;/blockquote>
&lt;h3 id="sparse-adaptation">Sparse adaptation&lt;/h3>
&lt;p>典型例子：DSA：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-071933.png" alt="image-20260708151933116" style="zoom:50%;" />
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-071944.png" alt="image-20260708151944610" style="zoom:50%;" />
&lt;p>虽然计算复杂度仍然是平方级别的，但因为有indexer的存在，导致复杂度的常数项小了很多，整体复杂度降低。&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-074344.png" alt="image-20260708154344081" style="zoom:50%;" />
&lt;blockquote>
&lt;p>参考资料：https://zhuanlan.zhihu.com/p/1959636888123049941&lt;/p>
&lt;/blockquote>
&lt;h3 id="moe">MOE&lt;/h3>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-090723.png" alt="image-20260708170723089" style="zoom:50%;" />
&lt;p>老式的MOE做法是：&lt;/p>
&lt;p>先计算出所有expert的routing logits，过一层softmax，把softmax的输出结果作为topk的score，再将topk的结果作为gating function，但这种方法会导致最后topk的概率和不为1，所以在之后的模型结构中，大部分改为在topk之后，只在selected experts上做softmax。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Shared experts&lt;/strong>&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-153534.png" alt="image-20260708233533511" style="zoom:50%;" />
&lt;p>对于shared expert能否提高效果，说法不一，但是将expert切的更细，即fine-grained expert。&lt;/p>
&lt;h4 id="train-moes">Train MOEs&lt;/h4>
&lt;p>虽然sparsity带来了训练阶段的高效性，但因为gating+topk操作不可微分，这给通过正常的梯度下降更新带来了困难；所以训练MOE模型需要一些trick。&lt;/p>
&lt;ul>
&lt;li>使用强化学习更新门控策略: 可以做，但是太复杂，不常用；&lt;/li>
&lt;li>增加随机扰动项(&lt;code>stochastic perturbations&lt;/code>)：&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-08-174546.png" alt="image-20260709014546143" style="zoom:50%;" />
&lt;ul>
&lt;li>启发式平衡loss(&lt;code>Heuristic balancing losses&lt;/code>)&lt;/li>
&lt;/ul>
&lt;p>在原版的total loss基础上，增加一个辅助loss（&lt;code>auxiliary loss&lt;/code>），目的：如果一个expert获得了过多的token，那么会压制接下来token选择该expert的概率。由两部分构成：&lt;/p>
&lt;p>$f_i$表示被路由到$E_i$的比例，$P_i$表示被路由到$E_i$的平均概率，那么：&lt;/p>
&lt;p>$$loss=\alpha N \sum_{i=1}^N f_i P_i$$&lt;/p>
&lt;ul>
&lt;li>需要有f，因为被路由的概率只是一个软性的指标，不代表最后dispatch的结果；&lt;/li>
&lt;li>需要有p，因为f不可微分，需要p作为可微入口，将梯度回传router；&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-091518.png" alt="image-20260709171517384" style="zoom:50%;" />
&lt;p>注意loss对$p_i(x)$的梯度为：$\frac{\alpha N}{T^2} \sum 1_{argmax\ p(x)=o}$，这意味着对某个expert更频繁的使用会导致梯度上升，从而对$p_i(x)$本身带来更强的压制（梯度下降更新）。&lt;/p>
&lt;blockquote>
&lt;p>一个典型例子是&lt;strong>switch transformer&lt;/strong>.&lt;/p>
&lt;/blockquote>
&lt;p>除了上述的&lt;strong>per-expert balancing&lt;/strong>之外，DeepSeek V1-2还引入了&lt;strong>per-device balancing&lt;/strong>，用来平衡不同device之间的负载：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-092900.png" alt="image-20260709172859481" style="zoom:50%;" />
&lt;p>在DeepSeek-V3中，又引入了&lt;strong>per-expert biases&lt;/strong>, 也被称为&lt;code>auxiliary loss free balancing&lt;/code>（其实并不能完全做到loss free）：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-113357.png" alt="image-20260709193357310" style="zoom:50%;" />
&lt;p>在打分结果上加上一个bias，对于接受token数量超过平均值的expert，降低bias，从而达到负载均衡的效果。&lt;/p>
&lt;h5 id="mla-multi-head-latent-attention">MLA (Multi-Head Latent Attention)&lt;/h5>
&lt;p>在DS V3中，使用了MLA来做KV状态的压缩。&lt;/p>
&lt;ul>
&lt;li>先前的问题是什么？&lt;/li>
&lt;/ul>
&lt;p>虽然KV cache这种&lt;strong>用空间换时间&lt;/strong>（&lt;strong>存储换计算&lt;/strong>）的方法，将计算复杂度从$O(N^2)$降低到了$O(N)$，但存在以下问题：&lt;/p>
&lt;ol>
&lt;li>kv cache的显存大小成为decoding瓶颈；&lt;/li>
&lt;li>计算量的下降，让decoding过程成为memory bound；&lt;/li>
&lt;li>为了提高计算强度，BS的增大又受到了1的制约；&lt;/li>
&lt;/ol>
&lt;p>所以思考，能否存在一种&lt;strong>折中&lt;/strong>方案？即沿用先前空间换时间的优化思路，但是不要那么激进？&lt;/p>
&lt;p>一个常用的改变计算强度的优化方法就是利用&lt;strong>矩阵结合律&lt;/strong>，和&lt;code>linear attention&lt;/code>类似：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-10-150510.png" alt="image-20260710230509865" style="zoom:50%;" />
&lt;p>这种方法也被叫做&lt;strong>矩阵吸收&lt;/strong>。经过改造后，原有的KV cache也被替代为：缓存前置的prefill的$N\times d$输入，即$X$.&lt;/p>
&lt;p>但定量分析后会发现，减少的KV cache比例远低于增加的计算量。所以需要一些技巧来进一步压缩存储：即&lt;strong>降维X&lt;/strong>：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-10-164505.jpg" alt="img" style="zoom:50%;" />
&lt;p>这样节省的KV cache比例进一步增大，可以平衡带来的计算开销。$X^TW_{DKV}$就是论文中的$C$，也即需要缓存的压缩表示。&lt;/p>
&lt;p>矩阵吸收的另一个潜在好处是，假使前提是要缓存$C$，矩阵吸收增加的计算复杂度（相比缓存正常的KV cache）相比于计算$W_k^{&amp;rsquo;}$和$W_v^{&amp;rsquo;}$来恢复原本的$K$ $V$矩阵增加的计算复杂度更低。&lt;/p>
&lt;ul>
&lt;li>为什么training和prefill阶段不需要做矩阵吸收？&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-10-172340.png" alt="image-20260711012340264" style="zoom:50%;" />
&lt;ul>
&lt;li>ROPE是如何与MLA共存的？&lt;/li>
&lt;/ul>
&lt;p>首先明确，为什么ROPE不能直接应用在MLA上？因为ROPE矩阵是一个和位置相关的矩阵，不是固定的，导致每次新的token都要重新计算，从而降低推理效率。&lt;/p>
&lt;p>解决方法：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-10-174336.png" alt="image-20260711014336160" style="zoom:50%;" />
&lt;blockquote>
&lt;p>具体参考：&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/1911795330434986569" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/1911795330434986569&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/16730036197" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/16730036197&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;h4 id="moe-stability">MOE stability&lt;/h4>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-114545.png" alt="image-20260709194545150" style="zoom:50%;" />
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-114600.png" alt="image-20260709194600066" style="zoom:50%;" />
&lt;h4 id="other-train-methods">other train methods&lt;/h4>
&lt;ul>
&lt;li>&lt;strong>Upcycling&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>使用预先训练好的dense模型，load到MOE模型上：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-09-114716.png" alt="image-20260709194716340" style="zoom:50%;" />
&lt;h2 id="gpus-tpus">GPUs TPUs&lt;/h2>
&lt;h3 id="tpu">TPU&lt;/h3>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-092520.png" alt="image-20260713172519789" style="zoom:50%;" />
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-092536.png" alt="image-20260713172536163" style="zoom:50%;" />
&lt;p>TPU与GPU在很多设计上相似，核心区别在于其处理矩阵乘的单元是一个大单元，而GPU是很多个小的tensor core单元来加速matmul的；同时两者对tensor core的定义不一样。&lt;/p>
&lt;h3 id="making-gpus-go-fast">Making GPUs go fast&lt;/h3>
&lt;p>这里主要讨论如何优化memory pass。&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-114018.png" alt="image-20260713194018164" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>Control divergence (not a memory issur)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>在同一时刻，同一warp中的所有线程处于同一代码段，如果不需要执行对应分支，则等待：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-114544.png" alt="image-20260713194544196" style="zoom:50%;" />
&lt;ul>
&lt;li>&lt;strong>Low precision computation&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>可以使用16bit(BF16/FP16)的操作：matrix ops、大部分pointwise操作（relu/add/sub/mul）；&lt;/p>
&lt;p>需要更高精度(FP32/FP16)的操作：reduction (sum/softmax/norm)，因为较小的值累加很容易出现rounding errors；&lt;/p>
&lt;p>需要使用更大range(FP32/BF16)的操作：返回结果比输入大很多的pointwise ops (exp, log, pow)，比如loss function；&lt;/p>
&lt;blockquote>
&lt;p>FP8 training:&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-124957.png" alt="image-20260713204957283" style="zoom:50%;" />
&lt;p>因为transpose会改变数据排布，需要重新计算scaling，所以MXFP8在内部quantize时，会一次性得到两个矩阵，其中一个用于transpose。&lt;/p>
&lt;/blockquote>
&lt;p>FP4省略。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Operator fusion&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>recomputation&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Memory coalescing and DRAM&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>tiling&lt;/strong>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-143823.png" alt="image-20260713223822361" style="zoom:50%;" />
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-145447.png" alt="image-20260713225447269" style="zoom:50%;" />
&lt;h4 id="wave-quantization">wave quantization&lt;/h4>
&lt;blockquote>
&lt;p>波量化（Wave Quantization）：&lt;strong>当计算任务超出GPU SM数量时，需要将计算任务分成多个waves进行执行，而这些wave被线性执行需要等待，导致性能下降&lt;/strong>。&lt;/p>
&lt;/blockquote>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-145557.png" alt="image-20260713225557436" style="zoom:50%;" />
&lt;h3 id="flash-attention">Flash Attention&lt;/h3>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-153008.png" alt="image-20260713233007674" style="zoom:50%;" />
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-13-153123.png" alt="image-20260713233122704" style="zoom:50%;" />
&lt;blockquote>
&lt;p>理解从3-pass softmax -&amp;gt; online softmax -&amp;gt; 1-pass flash attention的数学推导：https://zhuanlan.zhihu.com/p/668888063&lt;/p>
&lt;/blockquote>
&lt;h2 id="kernel-triton-xla">Kernel, Triton, XLA&lt;/h2>
&lt;h3 id="kernel-basic-concepts">kernel basic concepts&lt;/h3>
&lt;p>一些基本概念。&lt;/p>
&lt;h4 id="occupancy">occupancy&lt;/h4>
&lt;ul>
&lt;li>Each thread can use between 0 and 255 registers.&lt;/li>
&lt;li>The more registers threads use, the fewer threads can be scheduled on an SM (low occupancy).&lt;/li>
&lt;li>Low occupancy isn&amp;rsquo;t necessarily bad if each thread is doing more work.&lt;/li>
&lt;li>Example: thread coarsening (each thread processes multiple elements).&lt;/li>
&lt;li>Example: thread block has 64 threads, each using 160 registers, SM has 65536 registers&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># What we want to run&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_threads_per_block&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">128&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_registers_per_thread&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">160&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># What hardware offers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">max_registers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">65536&lt;/span> &lt;span class="c1"># Registers allowed per SM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">max_warps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">64&lt;/span> &lt;span class="c1"># Concurrent warps allowed per SM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># What we can run at once&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">assert&lt;/span> &lt;span class="n">num_registers_per_thread&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">255&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_registers_per_block&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num_threads_per_block&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">num_registers_per_thread&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_blocks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">max_registers&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="n">num_registers_per_block&lt;/span> &lt;span class="c1"># Limited by registers &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_warps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num_blocks&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">num_threads_per_block&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">32&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">occupancy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num_warps&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">max_warps&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="bank-conflicts">Bank Conflicts&lt;/h4>
&lt;p>同一个warp中的每个线程对share mem访问的是同一个bank中的地址（不是完全一样的地址，否则会触发broadcast）：&lt;/p>
&lt;img src="https://shaopu-blog.oss-cn-beijing.aliyuncs.com/img/2026-07-14-074056.png" alt="image-20260714154056371" style="zoom:50%;" />
&lt;h4 id="memory-coalescing">Memory coalescing&lt;/h4>
&lt;p>针对HBM：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">When&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="mi">32&lt;/span> &lt;span class="n">threads&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="n">warp&lt;/span> &lt;span class="n">access&lt;/span> &lt;span class="n">HBM&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">memory&lt;/span> &lt;span class="n">accesses&lt;/span> &lt;span class="n">combined&lt;/span> &lt;span class="n">into&lt;/span> &lt;span class="n">transactions&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="mi">128&lt;/span> &lt;span class="nb">bytes&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">cache&lt;/span> &lt;span class="n">lines&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">M00&lt;/span> &lt;span class="n">M01&lt;/span> &lt;span class="n">M02&lt;/span> &lt;span class="n">M03&lt;/span> &lt;span class="n">M04&lt;/span> &lt;span class="n">M05&lt;/span> &lt;span class="n">M06&lt;/span> &lt;span class="n">M07&lt;/span> &lt;span class="n">M08&lt;/span> &lt;span class="n">M09&lt;/span> &lt;span class="n">M10&lt;/span> &lt;span class="n">M11&lt;/span> &lt;span class="n">M12&lt;/span> &lt;span class="n">M13&lt;/span> &lt;span class="n">M14&lt;/span> &lt;span class="n">M15&lt;/span> &lt;span class="n">M16&lt;/span> &lt;span class="n">M17&lt;/span> &lt;span class="n">M18&lt;/span> &lt;span class="n">M19&lt;/span> &lt;span class="n">M20&lt;/span> &lt;span class="n">M21&lt;/span> &lt;span class="n">M22&lt;/span> &lt;span class="n">M23&lt;/span> &lt;span class="n">M24&lt;/span> &lt;span class="n">M25&lt;/span> &lt;span class="n">M26&lt;/span> &lt;span class="n">M27&lt;/span> &lt;span class="n">M28&lt;/span> &lt;span class="n">M29&lt;/span> &lt;span class="n">M30&lt;/span> &lt;span class="n">M31&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">M32&lt;/span> &lt;span class="n">M33&lt;/span> &lt;span class="n">M34&lt;/span> &lt;span class="n">M35&lt;/span> &lt;span class="n">M36&lt;/span> &lt;span class="n">M37&lt;/span> &lt;span class="n">M38&lt;/span> &lt;span class="n">M39&lt;/span> &lt;span class="n">M40&lt;/span> &lt;span class="n">M41&lt;/span> &lt;span class="n">M42&lt;/span> &lt;span class="n">M43&lt;/span> &lt;span class="n">M44&lt;/span> &lt;span class="n">M45&lt;/span> &lt;span class="n">M46&lt;/span> &lt;span class="n">M47&lt;/span> &lt;span class="n">M48&lt;/span> &lt;span class="n">M49&lt;/span> &lt;span class="n">M50&lt;/span> &lt;span class="n">M51&lt;/span> &lt;span class="n">M52&lt;/span> &lt;span class="n">M53&lt;/span> &lt;span class="n">M54&lt;/span> &lt;span class="n">M55&lt;/span> &lt;span class="n">M56&lt;/span> &lt;span class="n">M57&lt;/span> &lt;span class="n">M58&lt;/span> &lt;span class="n">M59&lt;/span> &lt;span class="n">M60&lt;/span> &lt;span class="n">M61&lt;/span> &lt;span class="n">M62&lt;/span> &lt;span class="n">M63&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Best&lt;/span> &lt;span class="k">case&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">full&lt;/span> &lt;span class="n">coalescing&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">all&lt;/span> &lt;span class="n">threads&lt;/span> &lt;span class="n">access&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">same&lt;/span> &lt;span class="n">cache&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">32&lt;/span> &lt;span class="n">threads&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="nb">bytes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">128&lt;/span> &lt;span class="nb">bytes&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="block-occupancy">Block occupancy&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Thread&lt;/span> &lt;span class="n">blocks&lt;/span> &lt;span class="n">scheduled&lt;/span> &lt;span class="n">onto&lt;/span> &lt;span class="n">SMs&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">waves&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">B200&lt;/span> &lt;span class="n">has&lt;/span> &lt;span class="mi">148&lt;/span> &lt;span class="n">SMs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">we&lt;/span> &lt;span class="n">launch&lt;/span> &lt;span class="mi">160&lt;/span> &lt;span class="n">thread&lt;/span> &lt;span class="n">blocks&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">first&lt;/span> &lt;span class="n">wave&lt;/span> &lt;span class="n">has&lt;/span> &lt;span class="mi">148&lt;/span> &lt;span class="n">blocks&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">second&lt;/span> &lt;span class="n">wave&lt;/span> &lt;span class="n">has&lt;/span> &lt;span class="mi">12&lt;/span> &lt;span class="n">blocks&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Wave&lt;/span> &lt;span class="n">quantization&lt;/span> &lt;span class="n">problem&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">last&lt;/span> &lt;span class="n">wave&lt;/span> &lt;span class="n">has&lt;/span> &lt;span class="n">fewer&lt;/span> &lt;span class="n">thread&lt;/span> &lt;span class="n">blocks&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">leaving&lt;/span> &lt;span class="n">some&lt;/span> &lt;span class="n">SMs&lt;/span> &lt;span class="n">idle&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">low&lt;/span> &lt;span class="n">block&lt;/span> &lt;span class="n">occupancy&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Solution&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">make&lt;/span> &lt;span class="n">number&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="n">thread&lt;/span> &lt;span class="n">blocks&lt;/span> &lt;span class="n">divide&lt;/span> &lt;span class="c1"># SMs.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="profiling">Profiling&lt;/h3>
&lt;p>torch自带的profiler，示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">profile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Callable&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num_warmups&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Warmup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num_warmups&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">run&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cuda&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">synchronize&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Run the code with the profiler&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">profiler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">profile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">activities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">ProfilerActivity&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CUDA&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">experimental_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_C&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_profiler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_ExperimentalConfig&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">verbose&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">prof&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">run&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cuda&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">synchronize&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Print out table&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">table&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prof&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">key_averages&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">table&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sort_by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cuda_time_total&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_name_column_width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">row_limit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Append to profiles.txt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;var/profiles.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;a&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Profile at &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ctime&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">table&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">table&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="triton">Triton&lt;/h3>
&lt;p>指定thread block做什么。&lt;/p>
&lt;p>会将数据加载到shared memory中，再写回global memory。&lt;/p>
&lt;p>Element-wise example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@triton.jit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">triton_gelu_kernel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num_elements&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Input starts at `x_ptr`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Output starts at `y_ptr`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># | T T T T T T T T | T T T T T T T T | T T T T T T T T | T T T T T T T T |&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># | Block 0 | Block 1 | Block 2 | Block 3 |&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pid&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">program_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Identifies the block&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pid&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span> &lt;span class="c1"># Starting index of this block&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Indices where this thread block should operate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">offsets&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Don&amp;#39;t read/write past the end of the tensor&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mask&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">offsets&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">num_elements&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Read&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">offsets&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">mask&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Approx gelu is 0.5 * x * (1 + tanh(sqrt(2/pi) * (x + 0.044715 * x^3)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Compute (tl.tanh doesn&amp;#39;t exist, use tanh(a) = (exp(2a) - 1) / (exp(2a) + 1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.79788456&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mf">0.044715&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tanh&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.5&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">tanh&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Store&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">store&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">offsets&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">mask&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>triton经过compile后生成PTX.&lt;/p>
&lt;p>Row-wise Example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@triton.jit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">triton_softmax_kernel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x_row_stride&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_row_stride&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num_cols&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">num_cols&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Process each row independently&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">row_idx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">program_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">col_offsets&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Read from global memory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x_start_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">row_idx&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x_row_stride&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x_start_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">col_offsets&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x_row&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptrs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">col_offsets&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">num_cols&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">float&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;-inf&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Compute&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x_row&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x_row&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_row&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">numerator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_row&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">denominator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">numerator&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y_row&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numerator&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">denominator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Write back to global memory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y_start_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">y_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">row_idx&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">y_row_stride&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">y_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">y_start_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">col_offsets&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">store&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y_ptrs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_row&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">col_offsets&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">num_cols&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果需要切分tile：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@triton.jit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">row_sum_kernel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">out_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">row&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">program_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Which row are we processing?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Accumulator for each thread&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># One row: T1 T2 T3 T4 | T1 T2 T3 T4 | T1 T2 T3 T4 (N = 12, BLOCK_SIZE = 4)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">acc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zeros&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">float32&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Loop over tiles&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cols&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_SIZE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mask&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cols&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">N&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">N&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">cols&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">mask&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">acc&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">x&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Final reduction from BLOCK_SIZE (all threads) to a scalar&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">acc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">store&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">out_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Matmul example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@triton.jit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">matmul_relu_kernel&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">c_ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Compute c = a &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">K&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># a is M x K, b is K x N, c is M x N&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stride_am&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stride_ak&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># How to navigate a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stride_bk&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stride_bn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># How to navigate b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stride_cm&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stride_cn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># How to navigate c&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BLOCK_M&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BLOCK_N&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BLOCK_K&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">constexpr&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># We are working on the (m, n)-th tile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pid_m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">program_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pid_n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">program_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Indices&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices_m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pid_m&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">BLOCK_M&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_M&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Row indices of a [BLOCK_M]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices_n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pid_n&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">BLOCK_N&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Column indices of b [BLOCK_N]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">indices_k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_K&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Row indices of a = column indices of b [BLOCK_K]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Initial matrix of pointers of a and b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_m&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_am&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_k&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_ak&lt;/span> &lt;span class="c1"># [BLOCK_M, BLOCK_K]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_k&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_bk&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_n&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_bn&lt;/span> &lt;span class="c1"># [BLOCK_K, BLOCK_N]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">acc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zeros&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">BLOCK_M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_N&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">float32&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Move along row tiles of a, column tiles of b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">K&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BLOCK_K&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a_ptrs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices_m&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">M&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">indices_k&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">K&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b_ptrs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices_k&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">k&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">K&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">indices_n&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">acc&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a_ptrs&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">BLOCK_K&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_ak&lt;/span> &lt;span class="c1"># Advance to the next row tile of a&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b_ptrs&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">BLOCK_K&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_bk&lt;/span> &lt;span class="c1"># Advance to the next column tile of b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Apply activation function (e.g., ReLU)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">acc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">maximum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">acc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Write output tile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">c_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_m&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_cm&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_n&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_cn&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">store&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_ptrs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">acc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">indices_m&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">M&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">indices_n&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这行代码将1d的&lt;code>indice_m&lt;/code>和&lt;code>indice_k&lt;/code>通过broadcast，变成2d的shape：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">a_ptrs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a_ptr&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_m&lt;/span>&lt;span class="p">[:,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_am&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">indices_k&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">:]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">stride_ak&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>