<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://wudi.io/feed.xml" rel="self" type="application/atom+xml" /><link href="http://wudi.io/" rel="alternate" type="text/html" /><updated>2025-02-21T08:03:30+00:00</updated><id>http://wudi.io/feed.xml</id><title type="html">Di Wu</title><subtitle>A programming engineer come from China.
</subtitle><author><name>Di Wu</name></author><entry><title type="html">Go 语言中函数按照值返回结构体，编译器会做哪些优化？</title><link href="http://wudi.io/optimizations-of-go-compiler-while-function-return-structure-by-value.html" rel="alternate" type="text/html" title="Go 语言中函数按照值返回结构体，编译器会做哪些优化？" /><published>2024-08-27T00:00:00+00:00</published><updated>2024-08-27T00:00:00+00:00</updated><id>http://wudi.io/optimizations-of-go-compiler-while-function-return-structure-by-value</id><content type="html" xml:base="http://wudi.io/optimizations-of-go-compiler-while-function-return-structure-by-value.html"><![CDATA[<h2 id="大小分析-size-analysis">大小分析 Size Analysis</h2>

<p>Go 编译器分析结构体的大小。小型结构体(通常最多几个字大小)是优化的候选对象。</p>
<pre><code class="language-go">type SmallToken struct {
    Type  byte
    Value uint16
}

type LargeToken struct {
    Type    byte
    Value   uint16
    Data    [1024]byte
}

func GetSmallToken() SmallToken { /* ... */ }  // 可能被优化
func GetLargeToken() LargeToken { /* ... */ }  // 不太可能被优化
</code></pre>

<h2 id="栈分配-stack-allocation">栈分配 Stack Allocation</h2>

<p>对于小型结构体,编译器通常在栈上而不是堆上分配它们。栈分配更快,不需要垃圾回收。</p>

<pre><code class="language-go">func ProcessToken() {
    token := SmallToken{Type: 1, Value: 100}  // 很可能在栈上分配
    // 使用 token...
}
</code></pre>

<h2 id="寄存器使用-register-usage">寄存器使用 Register Usage</h2>

<p>非常小的结构体(1-2个字)通常可以完全在 CPU 寄存器中返回,完全避免内存操作。</p>

<pre><code class="language-go">type Coordinate struct {
    X, Y int32
}

func GetCoordinate() Coordinate {
    return Coordinate{10, 20}  // 可能直接使用寄存器返回
}
</code></pre>

<h2 id="内联-inlining">内联 Inlining</h2>

<p>编译器可能会内联小函数,包括返回小型结构体的方法。这意味着函数的代码直接插入到调用点,消除了函数调用开销。</p>

<pre><code class="language-go">func IsPositive(c Coordinate) bool {
    return c.X &gt; 0 &amp;&amp; c.Y &gt; 0
}

func Process() {
    coord := GetCoordinate()
    if IsPositive(coord) {  // IsPositive 可能被内联
        // ...
    }
}
</code></pre>

<ul>
  <li>复制消除 Copy Elision</li>
</ul>

<p>在某些情况下,编译器可以消除不必要的结构体复制。如果返回的结构体立即被使用然后丢弃,编译器可能会直接在使用它的位置构造它。</p>

<pre><code class="language-go">func UseToken(t SmallToken) int {
    return int(t.Type) + int(t.Value)
}

func Process() {
    result := UseToken(GetSmallToken())  // 可能直接在 UseToken 的参数位置构造 token
    // ...
}
</code></pre>

<ul>
  <li>逃逸分析 Escape Analysis</li>
</ul>

<p>编译器执行逃逸分析以确定结构体是否需要在堆上分配。不逃逸出函数作用域的小型结构体可以留在栈上。</p>

<pre><code class="language-go">func CreateToken() SmallToken {
    return SmallToken{Type: 1, Value: 100}  // 不会逃逸,留在栈上
}

func CreateTokenPtr() *SmallToken {
    return &amp;SmallToken{Type: 1, Value: 100}  // 可能逃逸到堆上
}
</code></pre>

<ul>
  <li>优化调用者代码 Optimizing Caller Code</li>
</ul>

<p>编译器可以优化调用代码。如果调用者立即使用返回的结构体的字段,编译器可能会生成直接访问这些字段的代码,而不完全构造结构体。</p>

<pre><code class="language-go">func Process() {
    token := GetSmallToken()
    if token.Type == 1 {  // 编译器可能优化掉完整的 token 构造
        // ...
    }
}
</code></pre>

<ul>
  <li>向量化 Vectorization</li>
</ul>

<p>对于涉及多个小型结构体的操作,编译器可能会使用 SIMD (单指令多数据)指令并行处理它们。</p>

<pre><code class="language-go">func SumCoordinates(coords []Coordinate) int {
    sum := 0
    for i := 0; i &lt; len(coords); i++ {
        sum += coords[i].X + coords[i].Y  // 可能使用 SIMD 指令并行处理
    }
    return sum
}
</code></pre>

<ul>
  <li>填充优化 Padding Optimization</li>
</ul>

<p>编译器可能会重新排序结构体中的字段以最小化填充并优化内存布局,改善缓存使用。</p>

<pre><code class="language-go">type OptimizedStruct struct {
    a int64  // 8 字节
    b int32  // 4 字节
    c int16  // 2 字节
    d int8   // 1 字节
}  // 总共 15 字节,但会被填充到 16 字节
</code></pre>

<ul>
  <li>常量传播 Constant Propagation</li>
</ul>

<p>如果返回的结构体的某些字段是常量或可以在编译时确定,编译器可能会预先计算这些值。</p>

<pre><code class="language-go">const TokenTypeID = 1

func GetIDToken() SmallToken {
    return SmallToken{Type: TokenTypeID, Value: 100}  // Type 字段可能在编译时就确定
}
</code></pre>

<p>参考文档：</p>
<ul>
  <li>https://stackoverflow.com/questions/1422149/what-is-vectorization</li>
</ul>]]></content><author><name>Di Wu</name></author><summary type="html"><![CDATA[大小分析 Size Analysis]]></summary></entry><entry><title type="html">机器学习/大模型领域中召回率(Recall)和精确率(Precision)是什么意思？</title><link href="http://wudi.io/concept-of-recall-and-precision-in-machine-learning-or-llm.html" rel="alternate" type="text/html" title="机器学习/大模型领域中召回率(Recall)和精确率(Precision)是什么意思？" /><published>2024-08-14T00:00:00+00:00</published><updated>2024-08-14T00:00:00+00:00</updated><id>http://wudi.io/concept-of-recall-and-precision-in-machine-learning-or-llm</id><content type="html" xml:base="http://wudi.io/concept-of-recall-and-precision-in-machine-learning-or-llm.html"><![CDATA[<h2 id="召回率-recall">召回率 (Recall)</h2>

<p>一个简单的例子来解释”召回”(Recall)这个概念。
想象你是一个图书管理员，负责管理学校图书馆里的所有书籍。有一天，校长让你找出所有关于”恐龙”的书。</p>

<p>你找出了10本关于恐龙的书。
但实际上，图书馆里总共有12本关于恐龙的书。</p>

<p>在这个例子中，”召回”就是指你成功找到的相关书籍的比例。
计算方法：
召回率 = (找到的相关书籍数量) / (实际存在的相关书籍总数)</p>

<p>= 10 / 12 = 约83%</p>

<p>这个召回率表示，在所有实际存在的相关书籍中，你成功找到了83%。
在机器学习中，”召回”的概念也是类似的：</p>

<p>它衡量的是模型在所有应该被找到的内容中，实际上找到了多少。
高召回率意味着模型很少漏掉应该被识别的内容。</p>

<p>比如，在医疗诊断系统中，高召回率意味着系统能够找出大部分患有某种疾病的病人，很少有漏诊的情况。
记住，召回率高不等于模型就完美无缺。有时候，为了找到所有相关内容，模型可能会”宁可错杀一千，不可放过一个”，导致许多不相关的内容也被错误地包括进来。这就引出了另一个重要概念：”精确率”(Precision)。</p>

<h2 id="精确率-precision">精确率 (Precision)</h2>

<p>“精确率”(Precision)这个概念。我们可以继续使用图书馆的例子，这样你就能更容易理解精确率和召回率之间的区别。
想象你还是那个图书管理员，校长又给了你一个新任务：找出关于”宇宙”的书。</p>

<p>你找出了15本你认为是关于宇宙的书。
但仔细检查后，发现这15本中只有12本真正是关于宇宙的，另外3本其实是科幻小说。</p>

<p>在这个例子中，”精确率”就是指在你找到的书中，真正符合要求的比例。
计算方法：
精确率 = (正确找到的相关书籍数量) / (找到的所有书籍数量)
= 12 / 15
= 80%
这个精确率表示，在你找到的所有书中，80%确实是关于宇宙的。
在机器学习中，”精确率”的概念也是类似的：</p>

<p>它衡量的是模型预测为正确的结果中，实际上有多少是真正正确的。
高精确率意味着模型很少将不相关的内容错误地包括进来。</p>

<p>举个实际应用的例子：
想象有一个系统用来识别垃圾邮件。高精确率意味着系统标记为垃圾邮件的绝大多数确实是垃圾邮件，很少会错误地将重要邮件标记为垃圾邮件。
精确率和召回率的平衡：</p>

<p>高精确率： “宁可放过一些，也不错误标记”
高召回率： “宁可多标记一些，也不遗漏任何一个”</p>

<p>在实际应用中，我们常常需要在精确率和召回率之间找到平衡。这取决于具体的应用场景和需求。
比如，在医疗诊断中，我们可能更注重高召回率，以免漏掉任何可能患病的人。而在垃圾邮件过滤中，我们可能更注重高精确率，以免错误地过滤掉重要邮件。</p>]]></content><author><name>Di Wu</name></author><summary type="html"><![CDATA[召回率 (Recall)]]></summary></entry><entry><title type="html">联系我</title><link href="http://wudi.io/contact-me.html" rel="alternate" type="text/html" title="联系我" /><published>2020-11-21T00:00:00+00:00</published><updated>2020-11-21T00:00:00+00:00</updated><id>http://wudi.io/contact-me</id><content type="html" xml:base="http://wudi.io/contact-me.html"><![CDATA[<p>Github: <a href="https://github.com/wudi">wudi</a></p>

<p>Email: hi#wudi.io</p>

<p>WeChat: echowudi</p>]]></content><author><name>Di Wu</name></author><summary type="html"><![CDATA[Github: wudi]]></summary></entry></feed>