<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>湾儿子狐狸</title><link>https://baysonfox.com/</link><description>Recent content on 湾儿子狐狸</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>baysonfox</copyright><lastBuildDate>Sun, 28 Dec 2025 16:19:44 +0800</lastBuildDate><atom:link href="https://baysonfox.com/index.xml" rel="self" type="application/rss+xml"/><item><title>用Numpy实现批量梯度下降(BGD)</title><link>https://baysonfox.com/2025/12/28/bgd-from-scratch/</link><pubDate>Sun, 28 Dec 2025 16:19:44 +0800</pubDate><guid>https://baysonfox.com/2025/12/28/bgd-from-scratch/</guid><description>&lt;img src="https://cdn.nodeimage.com/i/AsX3ZTmQ8P1DY9sEou1frBlkpuhtbaMA.webp" alt="Featured image of post 用Numpy实现批量梯度下降(BGD)" />&lt;h2 id="0x01-前言">0x01 前言
&lt;/h2>&lt;p>本文中你将看到: 辱骂老登, 逆天实验, 从零手搓,&lt;/p>
&lt;h2 id="0x02-什么叫作这是你们的python实验">0x02 什么叫作这是你们的Python实验?
&lt;/h2>&lt;p>一日主播正在摸鱼，突然收到朋友发来的一份Python实验报告的&lt;em>拍屏&lt;/em>，遂点开阅读。&lt;br>
读完之后主播受到大量惊吓，为分享与为辱骂对方教师提供证据，特此节选一段:&lt;/p>
&lt;blockquote>
&lt;p>实验名称：机器学习中线性回归的Python实现&lt;br>
&amp;hellip;&lt;br>
线性回归表达式: \(Y = \theta_1X_1 + \theta_2X_2 + ... + \theta_nX_n + \theta_0\)&lt;br>
训练模型求解线性回归系数 \(\theta_1, \theta_2, \theta_3\).&lt;/p>&lt;/blockquote>
&lt;p>&lt;em>似乎很简单，对吧?&lt;/em>&lt;/p>
&lt;p>但是据朋友表示，除了线性代数之外，没有任何有关内容的学习与铺垫，包括但不限于:&lt;/p>
&lt;ul>
&lt;li>机器学习&lt;/li>
&lt;li>概率论与数理统计&lt;/li>
&lt;li>torch, numpy等一系列常用包的使用&lt;/li>
&lt;/ul>
&lt;p>等等.jpg&lt;/p>
&lt;p>究竟是哪门子**老师会去给学生布置这种邪门实验啊？？&lt;br>
这还是Python课吗.jpg&lt;/p>
&lt;h2 id="0x03-来都来了">0x03 来都来了
&lt;/h2>&lt;h3 id="拆解bgd">拆解BGD
&lt;/h3>&lt;p>毕竟实验报告上给出来的就只有BGD本体，那自然而然就得先理解一下这是个啥鬼东西了。&lt;br>
BGD的武魂真身：&lt;/p>
\[
\theta_j := \theta_j - \alpha \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)}) x_j^{(i)}
\]&lt;p>那么这些鬼东西都是些啥:&lt;/p>
&lt;ul>
&lt;li>\(\theta_j\): 参数，在这里就是线性回归的三个回归参数（aka 权重)&lt;/li>
&lt;li>\(\alpha\): 学习率&lt;/li>
&lt;li>\(m\): 样本数量&lt;/li>
&lt;li>\(h_\theta(x^{(i)})\): 预测值&lt;/li>
&lt;li>\(y^{(i)}\): 真实值&lt;/li>
&lt;li>\(x_j^{(i)}\): 第i个样本的第j个特征&lt;/li>
&lt;/ul>
&lt;h3 id="那它是怎么实现拟合的呢">那它是怎么实现拟合的呢?
&lt;/h3>&lt;p>本质上它的目的就是为了让预测结果和真实结果接近，也就是最小化预测结果与真实结果的差值，进而逼近原始的回归参数。&lt;br>
既然要最小化预测结果与真实结果的差值，那从直觉上就知道我们要最小化 \(\theta x^ - y\) 了，更准确来说，其实是距离最近。
所以其实应该是平方，对于题目给出的三变量而言，自然就是
\((\theta_1x_1 + \theta_2x_2 + \theta_3x_3 - y)^2\)。&lt;br>
可我们要动的是\(\theta\)，X和y都是固定的，那咋办呢？&lt;/p>
&lt;h3 id="代价函数-cost-function">代价函数 Cost Function
&lt;/h3>&lt;p>那我们可不可以给\(\theta\)来打个分呢？自然是可以的！&lt;/p>
&lt;p>不妨定义一个代价函数\(J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)})^2\)，其中
\(h_\theta(x^{(i)})\)为预测值，\(y^{(i)}\)为真实值，\(m\)为样本数量。（如果有人看出来了，是的，这就是MSE在整个batch上的表示）&lt;/p>
&lt;p>为什么要除m呢？因为我们求的是在每一个样本上\(\theta\)的代价。&lt;br>
为什么要再乘\(\frac{1}{2}\)呢？因为之后求导很方便（x. (平方会刚好被消去，导完之后方便不少)&lt;/p>
&lt;h3 id="梯度与偏导">梯度与偏导
&lt;/h3>&lt;p>&lt;em>虽然我们知道了什么是代价函数，换句话来说，知道了我们预测的好坏，可我们还是不知道怎么更新呀！&lt;/em>&lt;br>
还记得高中的好朋友导数吗？它有个大哥叫作偏导.jpg&lt;br>
既然我们的目的是最小化\(J(\theta)\)，那干嘛不直接给它求个导（因为是多元函数，在这里是偏导）呢？&lt;/p>
&lt;p>我们都知道，当一个函数的导数为0，就代表它达到了极值点，而对于这种函数来说(二次函数，开口向上)，我们可以放心的知道，当梯度为0的时候，我们到达的&lt;strong>一定是极小值点&lt;/strong>（实际上也是最小值点）。
而直接解\(\frac{\partial J(\theta)}{\partial \theta} = 0\)是无法得到\(\theta\)的，况且解它难度也不小。&lt;br>
而我们已经知道它的导数了，那我们不如直接减去它，如果导数是正的，在图上减去它就代表向左走；而如果导数是负的，减去它就代表向右走，反方向走，自然就能到达极值点。&lt;/p>
&lt;h3 id="一次下降多少">一次下降多少?
&lt;/h3>&lt;p>既然我们已经知道要怎么走了，那走多少呢？这时候就有了学习率\(\alpha\)。&lt;br>
它来决定一步走多远，如果\(\alpha\)越大，走的就越远，反之亦然。
自然，如果\(\alpha\)过小，走的就太慢，太阳下山了，你还在半山腰；&lt;br>
如果\(\alpha\)过大，走的就太快，容易扯着蛋，跑到另一头去，搞不好下一脚可能又走回来，甚至跑得更远。
这就变成了在山谷两边反复横跳，永远也落不到底。&lt;/p>
&lt;h3 id="回到bgd">回到BGD
&lt;/h3>&lt;p>让我们对代价函数\(J(\theta)\)，对每个\(\theta_j\)求偏导：&lt;br>
&lt;/p>
\[
\frac{\partial J(\theta)}{\partial \theta_j} = \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)}) x_j^{(i)}
\]&lt;p>挺熟悉的？你再看看BGD呢.jpg&lt;br>
实际上它就是BGD的梯度部分，也就是 Batch &lt;strong>Gradient&lt;/strong> Descent 的 &lt;strong>Gradient&lt;/strong>。
而前面的求和和除以m，就是BGD的&lt;strong>Batch&lt;/strong>了。&lt;br>
那 &lt;strong>Descent&lt;/strong> 呢？自然就是\(\theta_j := \theta_j - \alpha \)的部分了。&lt;/p>
&lt;h2 id="0x04-那怎么写呢">0x04 那怎么写呢?
&lt;/h2>&lt;p>在计算机的世界里，我们一直都在跟向量和矩阵打交道，而手写for循环拆解自然慢的发指。不过我们还有numpy!&lt;br>
我们大可以一条条处理再汇总，但是为什么不写成矩阵呢？&lt;br>
于是乎对于我们提到的预测值，输入自然可以变成一个\(m \times 3 \)的矩阵，输出自然就是一个\(m \times 1 \)的矩阵，
而真实值就会是一个\(m \times 1 \)的矩阵，\(\theta\)则是一个\(3 \times 1 \)的矩阵。&lt;/p>
&lt;p>在 Python 里，&lt;code>nupy.dot()&lt;/code> 或者 &lt;code>@&lt;/code> 都可以帮我们实现矩阵乘法，因此我们有:
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&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">predict&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">theta&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">np&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">X&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">theta&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;p>误差则直接可以通过&lt;code>error = predict(X, theta) - y&lt;/code>来计算，梯度就会变成&lt;code>gradients = X.T @ error / m&lt;/code>。&lt;br>
&lt;em>为什么是&lt;code>X.T&lt;/code>? 线性代数告诉我们，一个\(m \times 3\)的矩阵是没法和\(m \times 1\)的矩阵相乘的，自然就需要进行转置，因此是&lt;code>X.T&lt;/code>。&lt;/em>
更新权重就很简单了，&lt;code>theta = theta - alpha * gradients&lt;/code>。&lt;/p>
&lt;p>剩下的内容就很简单了，写一个循环把它们包起来就好，毕竟只优化一次也没什么用。&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">bgd&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="n">theta&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">alpha&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num_iters&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">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_iters&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">predict&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">theta&lt;/span>&lt;span class="p">)&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="n">gradients&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">T&lt;/span> &lt;span class="o">@&lt;/span> &lt;span class="n">error&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">m&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">theta&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">alpha&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">gradients&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">theta&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 id="0x05-一些善后工作">0x05 一些善后工作
&lt;/h2>&lt;p>回到实验报告，老登很贴心的不提供数据集，于是乎只好自己动手丰衣足食，来生成一组，顺便把\(\theta\)和学习率与迭代步数也初始化一下:&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="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">matplotlib.pyplot&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">plt&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">true_theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randn&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">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">X&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&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 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">true_theta&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">theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zeros&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">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">alpha&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">1e-2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_iters&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">800&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&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">true_theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randn&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">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">X&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">randn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&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 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">true_theta&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">theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zeros&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">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">alpha&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">1e-2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_iters&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&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">cost&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>&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_iters&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">error&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">predict&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">theta&lt;/span>&lt;span class="p">)&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="n">gradients&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">T&lt;/span> &lt;span class="o">@&lt;/span> &lt;span class="n">error&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">m&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">theta&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">theta&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">alpha&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">gradients&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cost&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">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mean&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">error&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;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;true theta&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">true_theta&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;learned theta&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">theta&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">plt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">plot&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cost&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">plt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">show&lt;/span>&lt;span class="p">()&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">theta: [[-0.53657517]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> [ 0.90257013]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> [-0.05914561]]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">true_theta: [[-0.53695188]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> [ 0.90310105]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> [-0.06005814]]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://cdn.nodeimage.com/i/nFnSfWYtK4TyfeHrngO5oWB0Nz8ikeW0.webp"
loading="lazy"
alt="cost 函数的图"
>&lt;/p></description></item><item><title>D2L: 用PyTorch和线性回归模型实现波士顿房价预测</title><link>https://baysonfox.com/2024/10/17/botson-house-linear-regression/</link><pubDate>Thu, 17 Oct 2024 14:26:40 +0000</pubDate><guid>https://baysonfox.com/2024/10/17/botson-house-linear-regression/</guid><description>&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/103976/18/52205/48713/6710ada3Fc993bbae/0fd577987fa47b40.png.avif" alt="Featured image of post D2L: 用PyTorch和线性回归模型实现波士顿房价预测" />&lt;h2 id="前言">前言
&lt;/h2>&lt;p>在大学选择人工智能专业以后，本来以为大一就会开始相关专业课的学习（框架，基础模型啥的），拿到大一上学期课程表一看，不能说是毫无关联，只能说是给其他人看都不知道你学人工智能.jpg&lt;br>
既然学校决定不在大一上学期（甚至下学习）开始专业课的学习，那就只好自己丰衣足食，先下手为强（bushi&lt;br>
P.S. 本文（以及后续可能有也可能没有的文章）基本上都是我在自己跟着&lt;a class="link" href="https://zh.d2l.ai" target="_blank" rel="noopener"
>Dive into Deep Learning&lt;/a>的过程中的一些实验与记录，里面的很多内容或许看起来很傻，或许对部分人来说理所当然，近乎常识，但我不知道，所以决定写写。（希望我大二系统性学之后回来看不会觉得自己太傻（&lt;/p>
&lt;p>在看完&lt;a class="link" href="https://zh.d2l.ai/chapter_linear-networks/linear-regression.html" target="_blank" rel="noopener"
>3.1. 线性回归&lt;/a>、&lt;a class="link" href="https://zh.d2l.ai/chapter_linear-networks/linear-regression-scratch.html" target="_blank" rel="noopener"
>3.2. 线性回归的从零开始实现&lt;/a>和 &lt;a class="link" href="https://zh.d2l.ai/chapter_linear-networks/linear-regression-concise.html" target="_blank" rel="noopener"
>3.3. 线性回归的简洁实现&lt;/a>后，&lt;del>突然感觉自己行了&lt;/del>，再加上之前听说过的线性回归经典例子：波士顿房价预测，于是决定自己跟着试一试，反正流程大同小异，对吧（&lt;/p>
&lt;h2 id="获取数据集">获取数据集
&lt;/h2>&lt;p>数据集的获取反倒相当简单，网络上哪哪都是（&lt;br>
我使用的数据集是 Kaggle 上的 &lt;a class="link" href="https://www.kaggle.com/datasets/vikrishnan/boston-house-prices/data" target="_blank" rel="noopener"
>Boston House Prices&lt;/a>，值得一提的是，这个数据集和经典版的数据集不太一样，&lt;strong>缺少&amp;quot;B&amp;quot;这一个Feature&lt;/strong>。&lt;br>
拉下来一看，经典csv.&lt;/p>
&lt;p>姑且还是把Features都说一说（也是为了水点字数）(翻译 by ChatGPT):&lt;/p>
&lt;ul>
&lt;li>CRIM: 每个镇的人均犯罪率&lt;/li>
&lt;li>ZN: 住宅用地比例，地块面积超过 25,000 平方英尺的比例&lt;/li>
&lt;li>INDUS: 每个镇的非零售商业用地比例&lt;/li>
&lt;li>CHAS: 查尔斯河虚拟变量（=1 表示地块毗邻河流；否则为 0）&lt;/li>
&lt;li>NOX: 氧化氮浓度（每 1000 万份中的份数）&lt;/li>
&lt;li>RM: 每个住宅的平均房间数&lt;/li>
&lt;li>AGE: 1940 年前建造的自有住房比例&lt;/li>
&lt;li>DIS: 到波士顿五个就业中心的加权距离&lt;/li>
&lt;li>RAD: 辐射公路的可达性指数&lt;/li>
&lt;li>TAX: 每 10,000 美元的全额物业税率&lt;/li>
&lt;li>PTRATIO: 每个镇的师生比例&lt;/li>
&lt;li>LSTAT: 低社会经济地位人口的百分比&lt;/li>
&lt;/ul>
&lt;h2 id="读取并处理数据集">读取并处理数据集
&lt;/h2>&lt;p>把数据集拉下来之后，多少要给它处理下，不然机器可看不懂（Code ahead）:&lt;br>
先看看数据集长啥样:&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">data_csv&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read_csv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;boston.csv&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">data_csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/237768/28/25873/78580/6710b33eFb8ab1ead/1894d886b2a2362c.png.avif"
loading="lazy"
alt="First 5 samples of Boston House Prices dataset"
>&lt;/p>
&lt;p>之后便是对数据集进行处理，分出 Features 和 Labels ，顺便把训练集和测试集也分下。
P.S. 为了接下来行文方便，&lt;strong>刻意省略了部分代码&lt;/strong>&lt;/p>
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&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"># CRIM, ZN ... LSTAT -&amp;gt; features&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># MEDV -&amp;gt; Labels&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">feature&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data_csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">drop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;MEDV&amp;#34;&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">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">label&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data_csv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;MEDV&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">feature_tensor&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">tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">feature&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&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">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"># Resizing the label tensor to corresponding size ([y] -&amp;gt; [y, 1])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">label_tensor&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">tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">label&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&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">float32&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">reshape&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 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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Create dataset&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TensorDataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">feature_tensor&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">label_tensor&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"># Train-Test split&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">train_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.8&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">train_size&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">train_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random_split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">train_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_size&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">train_iter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">train_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">batch_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shuffle&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="n">test_iter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">batch_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shuffle&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;/code>&lt;/pre>&lt;/div>
&lt;p>上面这段干的事其实很简单：&lt;/p>
&lt;ol>
&lt;li>先把 MEDV 给忽略掉，把 Features 单独提出来，再单独把 MEDV 提出来当 Labels.&lt;/li>
&lt;li>把&lt;code>feature&lt;/code>转换成张量&lt;code>feature_tensor&lt;/code>，方便接下来处理。&lt;/li>
&lt;li>同样，把&lt;code>label&lt;/code>转换成张量&lt;code>label_tensor&lt;/code>，但再&lt;code>.reshape&lt;/code>，给它的大小变成(-1, 1)，不然&lt;code>torch&lt;/code>回头会爆警告。&lt;/li>
&lt;li>用&lt;code>feature_tensor&lt;/code>, &lt;code>label_tensor&lt;/code> 创建一个叫作&lt;code>dataset&lt;/code>的&lt;code>TensorDataset&lt;/code>。&lt;/li>
&lt;li>把训练集和测试集分开。&lt;/li>
&lt;/ol>
&lt;h2 id="定义一个线性回归模型初始化权重">定义一个线性回归模型，初始化权重
&lt;/h2>&lt;p>在这里使用&lt;code>nn.Sequential&lt;/code>和&lt;code>nn.Linear&lt;/code>来创建模型.&lt;br>
引用一下D2L中对它们的描述:&lt;/p>
&lt;blockquote>
&lt;p>Sequential类将多个层串联在一起。 当给定输入数据时，Sequential实例将数据传入到第一层， 然后将第一层的输出作为第二层的输入，以此类推。&lt;br>
在PyTorch中，全连接层在Linear类中定义。 值得注意的是，我们将两个参数传递到nn.Linear中。 第一个指定输入特征形状，第二个指定输出特征形状，输出特征形状为单个标量，因此为1.&lt;/p>&lt;/blockquote>
&lt;p>对于D2L里的线性回归模型，编者们选择使用正态分布来初始化模型内参数的权重，在这里我也选择和他们一样，同时使用替换方法&lt;code>normal_&lt;/code>和&lt;code>fill_&lt;/code>来重写参数值。&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">net&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Sequential&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Linear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">12&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="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">net&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">weight&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">normal_&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.001&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">net&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">bias&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fill_&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;/code>&lt;/pre>&lt;/div>
&lt;h2 id="超参数-hyperparameters">超参数 (Hyperparameters)
&lt;/h2>&lt;p>&lt;em>训练的时候总是少不了超参数。&lt;/em>
&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">batch_size&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">lr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">1e-3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">num_epochs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">500&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;p>注: 同上，学习率&lt;code>lr&lt;/code>在这种情况下确实有问题，但先暂时不做改动。&lt;/p>
&lt;h2 id="损失函数与优化器">损失函数与优化器
&lt;/h2>&lt;p>对于 Loss function 和优化算法，依然与D2L保持一致，使用 &lt;code>MSELoss&lt;/code>类和&lt;code>SGD&lt;/code>.&lt;/p>
&lt;h3 id="背景知识何为mse">背景知识：何为MSE?
&lt;/h3>&lt;p>实际上，MSE看着高大上，实际上就是高中数学里概率统计里的方差，实际上，定义都完全一致:&lt;/p>
\[
\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} \left( y_i - \hat{y}_i \right)^2
\]&lt;p>其中:&lt;/p>
&lt;ul>
&lt;li>\(n\) 为数据点数量（既预测出的Feature的数量）&lt;/li>
&lt;li>\(y_i\) 是实际值（Ground Truth）&lt;/li>
&lt;li>\(\hat{y_i}\) 是模型的预测值&lt;/li>
&lt;li>\(y_i - \hat{y}\) 代表残差&lt;/li>
&lt;/ul>
&lt;p>MSE越小代表模型拟合的越小，反之.&lt;/p>
&lt;h3 id="背景知识何为sgd">背景知识：何为SGD?
&lt;/h3>&lt;p>&lt;em>我也不知道，但我以后也许会知道.&lt;/em>
&lt;em>这部分姑且留给以后学完高数的我来写.&lt;/em>&lt;/p>
&lt;p>建议参考: &lt;a class="link" href="https://www.cnblogs.com/guoyaohua/p/8542554.html" target="_blank" rel="noopener"
>深度学习——优化器算法Optimizer详解（BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam）&lt;/a>&lt;/p>
&lt;h2 id="训练启动">训练，启动
&lt;/h2>
&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">history&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="k">for&lt;/span> &lt;span class="n">epoch&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_epochs&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">X&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">train_iter&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loss&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">net&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">zero_grad&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">backward&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">step&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loss&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">net&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">feature_tensor&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">label_tensor&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;epoch &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">epoch&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, loss &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">f&lt;/span>&lt;span class="si">}&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">history&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">l&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>上面的代码总结起来，其实也就这么几件事:&lt;/p>
&lt;p>对每个mini batch (大小由超参数中的 &lt;code>batch_size&lt;/code> 决定):&lt;/p>
&lt;ol>
&lt;li>正向传播: 计算模型对这组 mini batch 的 loss.&lt;/li>
&lt;li>重置模型中每个参数的梯度.&lt;/li>
&lt;li>反向传播: 根据计算出的loss, 对权重矩阵\(\mathbf{W}\)中的每一个参数，计算它们的梯度，为下一步调整权重矩阵做准备.&lt;/li>
&lt;li>使用上一步计算得出的梯度调整模型的权重矩阵\(\mathbf{W}\).&lt;/li>
&lt;/ol>
&lt;p>当每一个 mini batch 都经历过一次计算后，便是一个 epoch .
而在每个 epoch 结束之后，计算出此时模型的 loss, 输出并记录.&lt;/p>
&lt;h2 id="理想很饱满现实很骨感">理想很饱满，现实很骨感
&lt;/h2>&lt;p>敲完代码，迫不期待按下执行，出问题了:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/148009/36/44199/13746/6710c3f3Fe450e12e/ffe5b3abbae75684.png.avif"
loading="lazy"
alt="Gradient explosion, resuting NaN loss"
>&lt;/p>
&lt;p>&lt;strong>不是，哥们。这不对吧?&lt;/strong>&lt;br>
&lt;em>这和说好的不一样啊!&lt;/em>&lt;/p>
&lt;p>那咋办呢？快请ChatGPT大仙!&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/91870/12/54317/32201/6710c6e4Fd6cbdc92/0115152f49f02755.png.avif"
loading="lazy"
alt="ChatGPT’s result of Gradient explosion"
>&lt;/p>
&lt;h2 id="梯度爆炸是什么">梯度爆炸是什么
&lt;/h2>&lt;p>ChatGPT是这么说的:&lt;/p>
&lt;blockquote>
&lt;p>梯度爆炸（Gradient Explosion）是深度学习中常见的一个问题，特别是在梯度反向传播时，某些参数的梯度变得非常大，导致模型参数更新过大，从而使得模型训练不稳定甚至发散。梯度爆炸可能是你在代码中出现 nan 问题的原因之一。&lt;/p>&lt;/blockquote>
&lt;p>既然提到了梯度，那还是不得不上公式:&lt;/p>
&lt;p>以下内容引用自 D2L 3.1.1.4 随机梯度下降:&lt;/p>
&lt;blockquote>
&lt;p>在每次迭代中，我们首先随机抽样一个小批量 \(\mathcal{B}\)， 它是由固定数量的训练样本组成的。 然后，我们计算小批量的平均损失关于模型参数的导数（也可以称为梯度）。 最后，将梯度乘以一个预先确定的正数\(\eta\)，并从当前参数的值中减掉。
我们用下面的数学公式来表示这一更新过程（表示偏导数）：
&lt;/p>
\[
(\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b)
\]&lt;p>
\(|\mathcal{B}|\)表示每个小批量中的样本数，这也称为批量大小（batch size）。 \(\eta\)表示学习率（learning rate）。&lt;/p>&lt;/blockquote>
&lt;h2 id="解决梯度爆炸-part-1">解决梯度爆炸 Part 1
&lt;/h2>&lt;p>梯度计算的简化理解:
&lt;/p>
\[
\begin{aligned}
\nabla_{\mathbf{x}} y = \frac{\partial L_{oss}}{\partial \mathbf{w}} \\
L_{oss} = \eta * \text{MSE}
\end{aligned}
\]&lt;p>如果MSE计算出来的loss太大，那就用一个超级小的learning rate 降下来就好了嘛（&lt;br>
于是乎，把lr给调到了一个超级小的值，(具体来说, 1e-7).&lt;br>
让我们再试一次:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/223437/33/46414/65918/6710ce1fFa3064a7d/d694b332348cff6d.png.avif"
loading="lazy"
alt="Decending speed of loss became very small after adjusting learning rate to a very small value"
>&lt;/p>
&lt;p>的确是能跑，loss也正常了，但是这下降速度也太慢了一点。&lt;br>
图里更直观一点:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/148609/9/46155/22143/6710ceadF31a6442f/258b6fd2de7268f3.png.avif"
loading="lazy"
alt="Train loss without normalize"
>&lt;br>
200个 epoch, loss 下降就那么点，对小数据集和小模型（比如线性回归）还好，毕竟一个 epoch 速度很快，但对大型模型来说，这要算到猴年马月。&lt;/p>
&lt;p>&lt;em>&amp;ldquo;ChatGPT，还有别的方法吗？&amp;rdquo;&lt;/em>&lt;/p>
&lt;h2 id="解决梯度爆炸-part-2">解决梯度爆炸 Part 2
&lt;/h2>&lt;p>ChatGPT 的回答:&lt;/p>
&lt;blockquote>
&lt;p>Unscaled Features:
In the code, it seems the features (input X) are used as-is from the dataset. The Boston dataset’s features (e.g., CRIM, ZN, etc.) may have widely varying scales. For example, CRIM might be in the range of [0, 100], whereas ZN might be in the range of [0, 10].&lt;br>
Large-scale values can cause instability in the gradient calculations, leading to nan values in the loss.&lt;br>
Solution: Standardize or normalize the features before feeding them into the model. You can do this by subtracting the mean and dividing by the standard deviation for each feature.&lt;/p>&lt;/blockquote>
&lt;p>太长不看版: &lt;strong>对Features做归一化/标准化&lt;/strong>.&lt;/p>
&lt;h3 id="那么归一化和标准化又是什么">那么，归一化和标准化又是什么
&lt;/h3>&lt;p>还是让ChatGPT来解释:&lt;/p>
&lt;blockquote>
&lt;p>归一化和标准化是数据处理中的两种常见技术，主要用于在进行机器学习、统计分析或优化问题时，使不同特征的数据保持在同一尺度上，以避免某些特征因为数值范围过大而主导模型。&lt;br>
归一化是将数据缩放到一个特定的范围，通常是 [0, 1] 或 [-1, 1]，其目的是使不同特征的数据具有相似的尺度。&lt;/p>&lt;/blockquote>
&lt;p>提取关键词: &lt;em>统一尺度&lt;/em> .&lt;br>
回到最开始的数据集, NOX 和 AGE 便是尺度不统一的最好例子.&lt;/p>
&lt;h3 id="用-min-max-来处理数据集中的不统一尺度">用 Min-Max 来处理数据集中的不统一尺度
&lt;/h3>&lt;p>此时，在数据集的处理里加几行代码，把特征先归一化，再进行接下来的处理:&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">feature_min&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">feature_tensor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">min&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">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">keepdim&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="n">feature_max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">feature_tensor&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">dim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">keepdim&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="n">feature_tensor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">feature_tensor&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">feature_min&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">feature_max&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">feature_min&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>本质上，上面的代码也只是干了以下这条公式干的事:&lt;br>
&lt;/p>
\[
X_{\text{new}} = \frac{X - X_{\text{min}}}{X_{\text{max}} - X_{\text{min}}}
\]&lt;p>此时数据集处理的完整代码:&lt;br>
&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">feature&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data_csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">drop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;MEDV&amp;#34;&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">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">label&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data_csv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;MEDV&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">feature_tensor&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">tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">feature&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&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">float32&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">label_tensor&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">tensor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">label&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&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">float32&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">reshape&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 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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">feature_min&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">feature_tensor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">min&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">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">keepdim&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="n">feature_max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">feature_tensor&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">dim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">keepdim&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="n">feature_tensor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">feature_tensor&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">feature_min&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">feature_max&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">feature_min&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">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TensorDataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">feature_tensor&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">label_tensor&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">train_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">0.8&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">train_size&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">train_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">random_split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">train_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_size&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">train_iter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">train_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">batch_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shuffle&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="n">test_iter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_dataset&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">batch_size&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shuffle&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;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;h2 id="继续训练">继续训练
&lt;/h2>&lt;p>在使用归一化处理数据之后，再来一遍训练：&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271017/175646/35/49263/20119/6710d4f1F3e661027/c3d4a4e51d77d2d7.png.avif"
loading="lazy"
alt="Train loss with normalize"
>&lt;/p>
&lt;p>好起来了，都好起来了.jpg&lt;/p>
&lt;h2 id="总结与优化可能">总结与优化可能
&lt;/h2>&lt;p>不得不说，自己从零开始，用其他数据集如法炮制，在出结果的那一刻还是很激动的，毕竟是自己实现的。&lt;/p>
&lt;p>再给自己留一些问题:&lt;/p>
&lt;ul>
&lt;li>除了SGD这一种Optimizer以外，还存在其他的Optimizer，比如RMSprop, Adam，尝试使用它们.&lt;/li>
&lt;li>更换不同的Loss function （比如Huber） 和 权重初始化方法，查看效果.&lt;/li>
&lt;/ul></description></item><item><title>使用MSVC和VSCode搭建C语言开发环境</title><link>https://baysonfox.com/2024/10/09/vscode-c-environment/</link><pubDate>Wed, 09 Oct 2024 23:26:40 +0000</pubDate><guid>https://baysonfox.com/2024/10/09/vscode-c-environment/</guid><description>&lt;img src="https://img30.360buyimg.com/img/jfs/t20271009/200262/3/45092/119332/6706967dF3a3731d0/812da67513989ad6.png.avif" alt="Featured image of post 使用MSVC和VSCode搭建C语言开发环境" />&lt;h2 id="温馨提示">温馨提示
&lt;/h2>&lt;ol>
&lt;li>本文可以基本理解为对&lt;a class="link" href="https://code.visualstudio.com/docs/languages/cpp" target="_blank" rel="noopener"
>https://code.visualstudio.com/docs/languages/cpp&lt;/a> 的直接翻译和部分精简, 如有条件可直接参考原文。&lt;/li>
&lt;li>对CUIT学生：本文仅供参考，仅为其中一种在你的机器上设置一个基础的用于学习C语言以及相关课程的环境，实际上其他开发环境，比如Dev-C++，Visual Studio （如果你会用的话）都没问题.&lt;/li>
&lt;li>依然是对CUIT学生：不建议（强烈不建议）自行更改MSYS2的安装目录（除非你知道在编辑环境变量那自己改过来），不然出问题别找我.jpg&lt;/li>
&lt;/ol>
&lt;h2 id="安装-vscode">安装 VSCode
&lt;/h2>&lt;ol>
&lt;li>访问 &lt;a class="link" href="https://code.visualstudio.com" target="_blank" rel="noopener"
>https://code.visualstudio.com&lt;/a>, 点击&amp;quot;Download for Windows&amp;quot;, 下载Visual Studio Code的安装包（注: 对CUIT的学生: 如果网络太差可以直接找我要）.
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271009/246518/22/19814/222162/67069829Fc3ea0894/3cd4347721bb6f5a.png.avif"
loading="lazy"
alt="下载VSCode"
>
之后, 点击下载下来的安装包 (它的名字应该类似&lt;code>VSCodeUserSetup-x86_64-1.94.1.exe&lt;/code>)，开始安装 (一路确认就好).&lt;/li>
&lt;/ol>
&lt;h2 id="在-vscode-里安装语言包和一些必要插件">在 VSCode 里安装语言包和一些必要插件
&lt;/h2>&lt;p>打开Visual Studio Code后，映入眼帘的大概率是全英文界面.&lt;/p>
&lt;ol>
&lt;li>在左侧的Extensions面板（或者说左上角的几个图标里最底下那个长得很像几个方块的那个图标，或者直接用Ctrl + Shift + X 调出）里，搜索&amp;quot;Chinese&amp;quot;, 点击第一个结果，安装&amp;amp;启用它。
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/242705/25/19209/726626/6707748aF7643b94e/561866756a8888f4.png.avif"
loading="lazy"
alt="Installing Chinese language pack"
>&lt;/li>
&lt;li>同样是在这个面板, 依次搜索 &amp;ldquo;C/C++ Extension Pack&amp;rdquo; 和 &amp;ldquo;Code Runner&amp;rdquo;, 依次安装并启用它们。
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/191347/33/48717/107689/670774e5F9e064b6f/776c53856cb67d30.png.avif"
loading="lazy"
alt="Installing C/C&amp;#43;&amp;#43; Extension Pack"
>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/222476/24/44805/76696/67077515Fb93b3f70/5a9ad1f35b7173ff.png.avif"
loading="lazy"
alt="Installing Code Runner extension"
>&lt;/li>
&lt;/ol>
&lt;p>第二步里安装的时候可能会提示很多东西，但暂时不需要理会它们。&lt;/p>
&lt;h2 id="安装msys2">安装MSYS2
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>访问 &lt;a class="link" href="https://www.msys2.org" target="_blank" rel="noopener"
>https://www.msys2.org&lt;/a>, 在&amp;quot;Installation&amp;quot;标题下，点击&amp;quot;Download the installer&amp;quot;旁边的按钮，下载MSYS2的安装包(现在 (2024/10/9), 叫作&lt;code>msys2-x86_64-20240727.exe&lt;/code> 同上，CUIT学生如果网络不好也可以找我要)
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/221097/35/44608/146681/67077076Ff8c828e7/2031493aae905dad.png.avif"
loading="lazy"
alt="Downloading MSYS2"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>打开之后也可以一路回车安装，安装耗时可能略久，但大部分情况下不会太久&lt;/p>
&lt;/li>
&lt;li>
&lt;p>假设你没有特地更改选项，那么安装完成（见图）之后应该会自动弹出一个黑色窗口，如图所示：
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/165593/19/49464/10547/670770c2F258218e8/9392ee647909a4a7.png.avif"
loading="lazy"
alt="MSYS2 Finished Installing"
>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271009/191163/21/49007/3624/67069babFb7e1e489/86d9dd2985bd931b.png.avif"
loading="lazy"
alt="MSYS2 Default Window"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在弹出的窗口内, 输入&lt;code>pacman -S --needed base-devel mingw-w64-x86_64-toolchain&lt;/code> （建议直接复制粘贴）(在MSYS2内，使用Shift + 鼠标左键，下同), 在提示&amp;quot;Enter a selection (default=all)&amp;ldquo;时直接enter确认，待它自动安装.
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/188945/10/48640/133274/6707710cF3b2e9136/167e68848fdbcc9f.png.avif"
loading="lazy"
alt="Installing MinGW-64"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在提示&lt;code>:: Proceed with installation? [Y/n]&lt;/code> 时输入Y确认安装.
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271013/167682/8/48677/48997/670b5bbbFf9b2c3b6/6ba999aa22e8efbc.png.avif"
loading="lazy"
alt="Proceed with installation"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在安装结束之后（你发现你可以随便输入命令，且回车能出现结果后），输入&lt;code>gcc -v&lt;/code>测试安装是否成功, 如果在底部附近出现了 &lt;code>gcc version&lt;/code> 的字样，说明安装应该没有什么问题。
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/192074/35/47476/36610/670771a7F83ccf8f9/69e3e05d0678fb62.png.avif"
loading="lazy"
alt="Picture displaying gcc’s version after installing MinGW toolchain"
>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="设置环境变量">设置环境变量
&lt;/h2>&lt;ol>
&lt;li>点击任务栏里的Windows图标, 输入&amp;quot;path&amp;rdquo;(或直接右击我的电脑-&amp;gt;属性-&amp;gt;高级系统设置), 选择 &amp;ldquo;编辑系统环境变量&amp;rdquo;, 在弹出窗口内选择“环境变量”.
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/173786/2/46030/22798/67077310Fbab51121/388f14b396654bf3.png.avif"
loading="lazy"
alt="Editing system PATH"
>&lt;/li>
&lt;li>在弹出窗口内的下半部分（系统变量）处，双击名称为&amp;quot;Path&amp;quot;的项目，在弹出窗口内点击&amp;quot;新建&amp;quot;, 输入&amp;quot;C:\msys64\ucrt64\bin&amp;quot;（或你自己设置的目录 绝大部分情况下，都是前述目录），点击确定保存.&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/103832/6/48773/273059/67077360Fbb8c5b67/baa5d7c889c1f714.png.avif"
loading="lazy"
alt="CleanShot 2024-10-10 at 14.24.51@2x"
>&lt;/li>
&lt;/ol>
&lt;h2 id="在vscode内设置编译器">在VSCode内设置编译器
&lt;/h2>&lt;ol>
&lt;li>安装好MSYS2，且设置好系统变量之后，回到VSCode，在主页（或者编辑器内任意处），按下&lt;code>Ctrl + Shift + P&lt;/code> (对macOS 用户来说, &lt;code>Command + Shift + P&lt;/code>), 在弹出的窗口内输入&amp;quot;C++ IntelliSense&amp;quot;, 点击“选择 IntelliSense 配置”
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/135572/25/49085/234536/67077675F775b2ccd/36fefa4547766f91.png.avif"
loading="lazy"
alt="Selecting IntelliSense configuration in VSCode"
>&lt;/li>
&lt;li>在弹出的窗口内，选择&amp;quot;gcc.exe&amp;quot;.
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/198731/34/44769/66683/67077701Ff78c4dd4/ded8471f49e4650a.png.avif"
loading="lazy"
alt="CleanShot 2024-10-10 at 14.40.12@2x"
>&lt;/li>
&lt;/ol>
&lt;h2 id="最终测试">最终测试
&lt;/h2>&lt;ol>
&lt;li>回到VSCode，新建文件，输入以下内容后按Ctrl + S 保存（建议直接复制粘贴）:&lt;/li>
&lt;/ol>
&lt;p>
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello World!&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="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="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/101218/28/52764/24880/67077408F2497acec/5cf394011d7fba0d.png.avif"
loading="lazy"
alt="VSCode window, displaying a “Hello World” program"
>&lt;br>
2. 在刚才的编辑窗口内，按下Ctrl + Alt + N (对macOS用户来说, Control + Option + N),如图所示, 如果在编辑器底部自动弹出了一个窗口，并且有&amp;quot;[Running]&amp;quot; 和 &amp;ldquo;[Done]&amp;rdquo; 字样，说明你完事了.jpg
&lt;img src="https://img30.360buyimg.com/img/jfs/t20271010/200315/25/46082/54303/67077443F3731575e/5ea4728d14b97846.png.avif"
loading="lazy"
alt="CleanShot 2024-10-10 at 14.28.47@2x"
>&lt;/p></description></item><item><title>AV1 的奇妙之旅: Part 2</title><link>https://baysonfox.com/2024/08/18/avif-av1-compress-part-two/</link><pubDate>Sun, 18 Aug 2024 00:00:00 +0000</pubDate><guid>https://baysonfox.com/2024/08/18/avif-av1-compress-part-two/</guid><description>&lt;img src="https://img30.360buyimg.com/img/jfs/t20270818/108923/20/51337/21774/66c0d894F34b74770/737acc2a60d4a0e1.jpg.avif" alt="Featured image of post AV1 的奇妙之旅: Part 2" />&lt;h2 id="前情提要">前情提要
&lt;/h2>&lt;p>在&lt;a class="link" href="https://baysonfox.com/2024/06/19/avif-av1-cosplay-compress/" target="_blank" rel="noopener"
>上一篇文章&lt;/a>里，我们初步的为了&lt;del>赶潮流&lt;/del> &lt;del>折腾&lt;/del> 宝贵的储存空间而决定投奔 AV1 编码之后，又过了那么个把月。这个把月自然是没有闲着，依然在捉摸着如何优化编码流程和效率。&lt;/p>
&lt;h2 id="python-加入战场">Python 加入战场
&lt;/h2>&lt;p>最开始的编码脚本完全基于一行 bash，不仅很蠢，也很容易出 bug（比如说带空格和特殊符号的文件），更没法搞定文件夹里的文件。&lt;br>
虽然大部分痛点可以用 find 和 xargs 之类的操作解决，但还是不够优雅，加之我也不习惯写 bash script，Python 还算是我的心头好，于是便用 Python 实现了一遍它的功能。&lt;/p>
&lt;p>代码如下:&lt;br>
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&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="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">subprocess&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">ffmpeg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">shlex&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">utils&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">get_keyint&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_video_resolution&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_tiles&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">return_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_img_size&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">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getcwd&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&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">path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;todo/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">video_extension&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.mp4&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.MP4&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.MOV&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.mov&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">image_extension&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.jpg&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.JPG&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.png&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.PNG&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;.jpeg&amp;#39;&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">video_files&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">image_files&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">log_lines&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dirs&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">files&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">walk&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">path&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">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">files&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">file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">endswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">video_extension&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">video_files&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">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&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">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&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">file&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">endswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">image_extension&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">image_files&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">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&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">root&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&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">for&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">video_files&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_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">return_path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;video&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">keyint&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_keyint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&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="p">,&lt;/span> &lt;span class="n">h&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_video_resolution&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_tiles&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">h&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ffmpeg_cmd&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">ffmpeg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">.&lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">.&lt;/span>&lt;span class="n">output&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_path&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vcodec&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;libsvtav1&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">acodec&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;copy&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">preset&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="n">crf&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">threads&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="o">**&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;svtav1-params&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;input-depth=10:tune=3:enable-qm=1:qm-min=0:enable-dlf=2:sc-pix-format=yuv420p:keyint=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">:tile-rows=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">:tile-columns=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">keyint&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&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="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">overwrite_output&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="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">for&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">image_files&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_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">return_path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;image&amp;#39;&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="p">,&lt;/span> &lt;span class="n">h&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_img_size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_tiles&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">h&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">avifenc_cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> avifenc &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --min 0 --max 63 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a enable-chroma-deltaq=1 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --autotiling &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a quant-b-adapt=1 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a sb-size=64 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a tune=ssim &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a deltaq-mode=2 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a row-mt=0 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a cpu-used=4 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a tune-content=psy &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --jobs 8 -s 3 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -d 10 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">shlex&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">shlex&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_path&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">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">avifenc_cmd&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shell&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;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;p>不妨细细展开，先从比较简单的图片讲起。&lt;/p>
&lt;h3 id="图片处理">图片处理
&lt;/h3>&lt;p>抛开各种有的没的的文件处理与各种东西，最重要的部分如下:&lt;br>
&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">for&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">image_files&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_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">return_path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;image&amp;#39;&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="p">,&lt;/span> &lt;span class="n">h&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_img_size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_tiles&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">h&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">avifenc_cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> avifenc &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --min 0 --max 63 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a enable-chroma-deltaq=1 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a enable-qm=0 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --autotiling &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a quant-b-adapt=1 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a sb-size=64 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a tune=ssim &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a deltaq-mode=2 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a cpu-used=4 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -a tune-content=psy &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> --jobs 8 -s 3 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> -d 10 &lt;/span>&lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">shlex&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">shlex&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_path&lt;/span>&lt;span class="p">))&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;p>流程分解:&lt;/p>
&lt;ol>
&lt;li>获取图片的分辨率&lt;/li>
&lt;li>用 &lt;code>avifenc&lt;/code> 编码 (最终依然会回到 &lt;code>aomenc&lt;/code>)&lt;/li>
&lt;/ol>
&lt;p>&lt;em>看着很简单，对吧？&lt;/em> 因为它确实很简单。重点在 &lt;code>avifenc_cmd&lt;/code> 的那一坨参数上，这帮鬼东西占据了我这段时间的相当一部分精力。&lt;/p>
&lt;p>让我们再次一行行展开：
&lt;em>注：所有以 &amp;ldquo;-a&amp;rdquo; 开头的参数全部会被直接传到 aomenc，因此在后面不再特地强调 &amp;ldquo;-a&amp;rdquo; 本身。&lt;/em>&lt;/p>
&lt;ol>
&lt;li>&lt;code>--min 0 --max 63&lt;/code>: 这俩参数其实没啥好说的，单纯限制一下颜色量化，实测下能在肉眼难以辨别的情况下比较有效的减小文件体积。&lt;/li>
&lt;li>&lt;code>enable-chroma-deltaq=1&lt;/code>: 它和下面的&lt;code>enable-qm=0&lt;/code>这俩参数就比较有意思了，更多属于偏经验主义，似乎会比一般情况下快不少……？&lt;/li>
&lt;li>&lt;code>enable-qm=0&lt;/code>: 官方文档中特别提到了 &amp;ldquo;default is 0 for allintra mode, 1 for good and realtime modes&amp;rdquo;，对于视频编码来说将它设置为 1 会更好，但对于图片这种 allintra （即全部为关键帧）的情况来说，可以设置为0.&lt;/li>
&lt;li>&lt;code>tune=ssim&lt;/code>: 先暂时跳过中间的参数，放到后面再讲，就本质上来说&lt;code>tune=ssim&lt;/code>能够相比&lt;code>psnr&lt;/code>做到更好的针对画质优化。&lt;/li>
&lt;li>&lt;code>--jobs 8 -s 3&lt;/code>: 设置8线程编码，speed 为 3. (speed 为 0-10, 越低越慢，质量越好)&lt;/li>
&lt;li>&lt;code>-d 10&lt;/code>: 本质上也是半经验主义参数。手动设置输入为 10bit 可以有效减小 aomenc 里对各种参数计算时的取整操作，进一步提升编码效率。&lt;/li>
&lt;/ol>
&lt;p>至于其他的参数，都基本源于在 Discord 的一场讨论：&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270818/47540/28/26065/97381/66c17375F35619f22/59c5451855888877.png.avif"
loading="lazy"
alt="202408181207736"
>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270818/242413/6/15259/355499/66c17399F6e3d545d/d9f0ed68f89dc22e.png.avif"
loading="lazy"
alt="CleanShot 2024-08-18 at 12.07.42@2x"
>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270818/232894/6/23322/518442/66c173b4F0b8e843c/c2bc6ca797ce05cd.png.avif"
loading="lazy"
alt="CleanShot 2024-08-18 at 12.08.06@2x"
>&lt;/p>
&lt;p>太长不看版: &lt;code>--autotiling --quant-b-adapt=1 --sb-size=64 --deltaq-mode=2 --cpu-used=4 --tune-content=psy&lt;/code>.&lt;br>
TODO: 对这几个参数的详细解释&lt;/p>
&lt;h3 id="视频处理">视频处理
&lt;/h3>&lt;p>同样，上代码：&lt;br>
&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">for&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">video_files&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_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">return_path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;video&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">keyint&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_keyint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&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="p">,&lt;/span> &lt;span class="n">h&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_video_resolution&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_tiles&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">h&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ffmpeg_cmd&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">ffmpeg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">.&lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">.&lt;/span>&lt;span class="n">output&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_path&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vcodec&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;libsvtav1&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">acodec&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;copy&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">preset&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="n">crf&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">40&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">threads&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="o">**&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;svtav1-params&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;input-depth=10:tune=3:enable-qm=1:qm-min=0:enable-dlf=2:keyint=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">:tile-rows=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">:tile-columns=&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">keyint&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&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="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">overwrite_output&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="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/p>
&lt;p>视频的编码流程就会相对复杂一些，首先用 &lt;code>keyint&lt;/code> 得到关键帧间隔（帧率*10）, 再用&lt;code>get_video_resolution&lt;/code>和&lt;code>get_tiles&lt;/code>获取&lt;code>tile-rows&lt;/code>和&lt;code>tile-columns&lt;/code>（本质上和图片部分的&lt;code>--autotiling&lt;/code>）是一样的。&lt;/p>
&lt;p>其他参数就和图片部分没啥大差别了，但还是要特别提及一下&lt;code>tune=3&lt;/code>: 在默认的 SVT-AV1 下是不存在 &lt;code>tune=3&lt;/code> 的设置的，只存在&lt;code>tune=2&lt;/code>（即SSIM），这里我使用了 &lt;a class="link" href="https://github.com/gianni-rosato/svt-av1-psy" target="_blank" rel="noopener"
>SVT-AV1-PSY&lt;/a>, 额外添加了SSIM with Subjective Quality Tuning作为&lt;code>tune=3&lt;/code>，更好改善画质.&lt;/p>
&lt;p>我所用到的 Python 脚本也都上传到了GitHub: &lt;a class="link" href="https://github.com/baysonfox/avif-compression" target="_blank" rel="noopener"
>https://github.com/baysonfox/avif-compression&lt;/a>&lt;/p></description></item><item><title>在VSCode上使用配置文件</title><link>https://baysonfox.com/2024/07/09/using-profiles-in-vscode/</link><pubDate>Tue, 09 Jul 2024 16:37:40 +0000</pubDate><guid>https://baysonfox.com/2024/07/09/using-profiles-in-vscode/</guid><description>&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/35830/29/23255/11392/66c0a9d7F58a21302/58c8f125dd2e6949.png.avif" alt="Featured image of post 在VSCode上使用配置文件" />&lt;h2 id="前言">前言
&lt;/h2>&lt;p>在使用配置文件之前，我机器上的 VSCode 可谓是插件大杂烩：各种为了不同文件格式的 Linter / Formatter 堆在一起，亦或是 Hugo 的各类实用工具让我找不着北，甚至拖慢启动速度，的确不能忍。&lt;/p>
&lt;p>作为多少有点开发环境“赛博洁癖”的一员，决定重新把自己的 VSCode 环境推倒重新来过，在此顺便记载一下过程。&lt;/p>
&lt;h2 id="在-vscode-上使用配置文件">在 VSCode 上使用配置文件
&lt;/h2>&lt;p>为了更好的把各路适用于不同场景的插件彻底分开，曾经尝试过用 Workspace 做区分，对每一个文件夹（比如baysonfox.com的源代码和其他的个人项目，亦或是写的小工具脚本，就用上了配置文件。&lt;/p>
&lt;p>创建一个配置文件倒也很简单，在左下角的齿轮处就有一个配置文件的选单，直接从那里选择新建一个配置文件，再指定名称就好。&lt;/p>
&lt;p>&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/58879/12/26267/34842/66c0a9feF8b61f101/5f66da6b55a142bb.png.avif"
loading="lazy"
alt="在 VSCode 上创建配置文件"
>&lt;/p>
&lt;h2 id="python-的配置文件魔改官方">Python 的配置文件：魔改官方
&lt;/h2>&lt;p>大体来讲，Python 的配置文件基本可以说是照抄 VSCode 的官方文档 &lt;a class="link" href="https://code.visualstudio.com/docs/editor/profiles#_profile-templates" target="_blank" rel="noopener"
>https://code.visualstudio.com/docs/editor/profiles#_profile-templates&lt;/a> 里的 Data Science Profile Template 和 Python Profile Template，但我又根据自己的习惯（也以尽量精简化的角度考虑），进行了一些改动：&lt;/p>
&lt;p>在 Python Profile Template 中，去掉了Docker, Even Better TOML 和 Black Formatter。 去掉 Docker 是因为我在写 Python 的时候并不会用到 Docker；
Even Better TOML 理由也几乎相同，我没有编辑 toml 的需求。而至于 Black Formatter，我所用到的功能无非只是一个格式化，也没有太强的格式需求，它的角色已经可以被 Ruff 完全替代，因此将其删除。&lt;/p>
&lt;p>在 Data Science Profile Template 中，我选择了里面的 Data Wrangler 与 Jypyter。不安装 Dev Containers 的理由同 Docker，而 GitHub Copilot 则暂时被 Codeium 取代（或许会等我搞到 GitHub 学生包之后再换回去）。&lt;/p>
&lt;p>习惯使然，主题方面我使用的是 Monokai Pro。&lt;/p>
&lt;p>总结一下：在各种删删改改之后，我最终的插件列表如下:&lt;/p>
&lt;ol>
&lt;li>autoDocstring (njpwerner.autodocstring)&lt;/li>
&lt;li>Codeium (Codeium.codeium)&lt;/li>
&lt;li>Data Wrangler (ms-toolsai.datawrangler)&lt;/li>
&lt;li>Monokai Pro (monokai.theme-monokai-pro-vscode)&lt;/li>
&lt;li>Pylance (ms-python.vscode-pylance)&lt;/li>
&lt;li>Python (ms-python.python)&lt;/li>
&lt;li>Python Environment Manager (donjayamanne.python-environment-manager)&lt;/li>
&lt;li>Ruff (charliermarsh.ruff)&lt;/li>
&lt;/ol>
&lt;p>大部分插件基本上都是开箱即用，但是 Ruff 还需要额外进行一些配置，在打开的项目下新建一个 &lt;code>ruff.toml&lt;/code>，在里面指定好需要的检查就好。&lt;br>
（可参考 &lt;a class="link" href="https://blog.davidz.cn/post/aio-ruff" target="_blank" rel="noopener"
>https://blog.davidz.cn/post/aio-ruff&lt;/a>。）&lt;/p>
&lt;h2 id="hugo-的配置文件从零开始">Hugo 的配置文件：从零开始
&lt;/h2>&lt;p>我本以为我的配置文件会相当复杂，但插件反而比 Python 要少不少，大多数就只是 Markdown 和 Hugo 相关。&lt;br>
直接上列表：&lt;/p>
&lt;ol>
&lt;li>markdownlint (DavidAnson.vscode-markdownlint)&lt;/li>
&lt;li>Hugo Language and Syntax Highlight (budparr.language-hugo-vscode)&lt;/li>
&lt;li>Front Matter CMS (eliostruyf.vscode-front-matter)&lt;/li>
&lt;li>hugofy (akmittal.hugofy)&lt;/li>
&lt;li>Hugo Shortcode Syntax Highlight (kaellarkin.hugo-shortcode-syntax)&lt;/li>
&lt;/ol>
&lt;p>这些插件的主要作用都是改善 QoL (&lt;strong>Q&lt;/strong>uality &lt;strong>o&lt;/strong>f &lt;strong>L&lt;/strong>ife) 的提升，markdownlint 负责格式，两个 Syntax Highlight 负责高亮，&lt;br>
而 Front Matter CMS 的作用更像是一个在 VSCode 里的面板，便于直接管理文章，而不用在命令行里手敲&lt;code>hugo new&lt;/code>创建文章。&lt;/p>
&lt;h2 id="装模作样的结尾">装模作样的结尾
&lt;/h2>&lt;p>差不多就是这样，&lt;del>又水了一篇 blog&lt;/del>。虽然自从去年换了 M2 Pro 之后，VSCode 的启动速度都相当快，但还是对 VSCode 做了些优化与配置分离，毕竟各种插件混着放在一起，看的不仅心里不舒服，有时还会冲突打起架，搞得心烦意燥，改完之后终于舒服了些。&lt;/p></description></item><item><title>用 AVIF 和 AV1 压缩 Cosplay 图库的体积</title><link>https://baysonfox.com/2024/06/19/avif-av1-cosplay-compress/</link><pubDate>Wed, 19 Jun 2024 00:00:00 +0000</pubDate><guid>https://baysonfox.com/2024/06/19/avif-av1-cosplay-compress/</guid><description>&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/242001/17/15436/39082/66c09017F03027e81/d726acbc1a6a2584.png.avif" alt="Featured image of post 用 AVIF 和 AV1 压缩 Cosplay 图库的体积" />&lt;p>编辑历史:&lt;/p>
&lt;ul>
&lt;li>2024/06/29 更新 AV1 部分调参内容&lt;/li>
&lt;li>2024/08/18 介于接下来的内容还放在这过于冗长，又多开了一篇：&lt;a class="link" href="https://baysonfox.com/2024/08/18/avif-av1-compress-part-two/" target="_blank" rel="noopener"
>https://baysonfox.com/2024/08/18/avif-av1-compress-part-two/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="事出必有因">事出必有因
&lt;/h2>&lt;p>前几天闲来无事，于是打算看下自己的 Cosplay 收藏有多少，遂&lt;code>du -sh&lt;/code>，结果如下:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/226766/37/23285/23993/66c0a3f3Fb9c4ca77/db8ba79127a8f4c8.png.avif"
loading="lazy"
alt="Cosplay文件夹占用了354G的储存空间"
>&lt;br>
&lt;strong>这可不好.jpg&lt;/strong>&lt;br>
于是点进去准备一探究竟，看看图片有多吃空间:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/243652/15/14618/18199/66c0a84aFdf651670/15b6fa6711eaad18.png.avif"
loading="lazy"
alt="图片的大小"
>&lt;br>
这能忍？开干！&lt;/p>
&lt;h2 id="那咋整呢">那咋整呢？
&lt;/h2>&lt;p>摆在面前的有三种选择：&lt;/p>
&lt;ul>
&lt;li>JPEG XL&lt;/li>
&lt;li>AVIF&lt;/li>
&lt;li>WebP&lt;/li>
&lt;/ul>
&lt;p>于是查阅互联网，找到一篇来自 &lt;a class="link" href="https://moonvy.com" target="_blank" rel="noopener"
>Moonvy 月维&lt;/a> 的&lt;a class="link" href="https://moonvy.com/blog/post/2022/next-generation-Image-format-2022/" target="_blank" rel="noopener"
>文章&lt;/a>。&lt;br>
直接上结论:&lt;/p>
&lt;blockquote>
&lt;p>AVIF 有损压缩效果最好，无损压缩非常糟糕。编码速度很慢。&lt;br>
JPEG XL 无损压缩效果最好，有损压缩较 AVIF 有些许差距。编码速度快。&lt;br>
WebP 2 无损压缩效果优秀，有损压缩的上限达到了 AVIF 的水平，但下限很低，不稳定。编码速度很慢。&lt;br>
但是考虑到未来可能还有网页浏览的需求，再加上 WebP 2 本身就没法在我的林檎OS(也就是 macOS)上正常浏览，且可以接受一定程度的有损压缩，于是直接冲 AVIF。&lt;/p>&lt;/blockquote>
&lt;h2 id="支线任务-装上-libavif">支线任务: 装上 libavif
&lt;/h2>&lt;p>决定好要用 AVIF，但是系统里大概率没有&lt;code>libavif&lt;/code>，于是先装再说。&lt;br>
介于我用 macOS ，直觉便是&lt;code>brew search avif&lt;/code>，&lt;code>brew install libavif&lt;/code>，秒了。&lt;br>
但是，古人曾言:&lt;/p>
&lt;blockquote>
&lt;p>AVIF 是这样的。林檎用户只要无脑装&lt;code>libavif&lt;/code>就可以，可是其他系统的用户要考虑的事就很多了。&lt;/p>&lt;/blockquote>
&lt;p>各路 Linux 玩家往这里看：&lt;a class="link" href="https://web.dev/articles/compress-images-avif" target="_blank" rel="noopener"
>https://web.dev/articles/compress-images-avif&lt;/a>；&lt;br>
至于 Windows ， &lt;em>自求多福&lt;/em>。&lt;/p>
&lt;h2 id="avif-启动">AVIF, 启动
&lt;/h2>&lt;p>毕竟是尺度有那么一丢丢大的 Cosplay (真的只有一丢丢！)，所以没有对比图（&lt;br>
处理用的命令如下：&lt;/p>
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">avifenc --min &lt;span class="m">0&lt;/span> --max &lt;span class="m">63&lt;/span> -a end-usage&lt;span class="o">=&lt;/span>q -a cq-level&lt;span class="o">=&lt;/span>&lt;span class="m">18&lt;/span> -a &lt;span class="nv">tune&lt;/span>&lt;span class="o">=&lt;/span>ssim &lt;span class="se">\ &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-a deltaq-mode&lt;span class="o">=&lt;/span>&lt;span class="m">3&lt;/span> -a &lt;span class="nv">sharpness&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">3&lt;/span> -y &lt;span class="m">420&lt;/span> --jobs &lt;span class="m">8&lt;/span> --ignore-exif --ignore-xmp Coser-***.jpg Coser-***.avif&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>至于为什么是这么个参数，原文是这么说的：&lt;/p>
&lt;blockquote>
&lt;p>Note: &amp;ldquo;&amp;ndash;min 0 &amp;ndash;max 63 -a end-usage=q -a cq-level=18 -a tune=ssim&amp;rdquo; are the recommended settings for AVIF images.&lt;/p>&lt;/blockquote>
&lt;p>而&lt;code>--ignore-exif --ignore-xmp&lt;/code> 为的是尽可能减小文件体积，反正 Exif 和 XMP 大概率都没啥用。&lt;/p>
&lt;details>
&lt;summary>结果：&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Successfully loaded: Coser-***.jpg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">AVIF to be written: (Lossy)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Resolution : 7952x5304
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Bit Depth : 8
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Format : YUV420
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Chroma Sam. Pos: 0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Alpha : Absent
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Range : Full
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Color Primaries: 2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Transfer Char. : 2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Matrix Coeffs. : 6
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- ICC Profile : Present (3144 bytes)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- XMP Metadata : Absent
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Exif Metadata : Absent
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Transformations: None
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Progressive : Unavailable
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Encoding with AV1 codec &amp;#39;aom&amp;#39; speed [6], color quality [51 (Medium)],
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> alpha quality [100 (Lossless)], tileRowsLog2 [0], tileColsLog2 [0],
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 8 worker thread(s), please wait...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Encoded successfully.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Color AV1 total size: 1334940 bytes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Alpha AV1 total size: 0 bytes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Wrote AVIF: Coser-***.avif&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/details>
&lt;p>再看看图片大小(下方为原图):&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/21356/16/22964/15080/66c0a881F512aa315/7665e05258bcafd2.png.avif"
loading="lazy"
alt="JPEG格式的原图和AVIF格式下的图片大小对比"
>&lt;br>
&lt;strong>效果立竿见影&lt;/strong>&lt;br>
93%的压缩率，很难不觉得 AVIF 不香。&lt;/p>
&lt;p>随便写个小脚本:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> file in *.&lt;span class="o">{&lt;/span>jpg,JPG&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="k">do&lt;/span> avifenc --min &lt;span class="m">0&lt;/span> --max &lt;span class="m">63&lt;/span> -a end-usage&lt;span class="o">=&lt;/span>q -a cq-level&lt;span class="o">=&lt;/span>&lt;span class="m">18&lt;/span> -a &lt;span class="nv">tune&lt;/span>&lt;span class="o">=&lt;/span>ssim &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -a deltaq-mode&lt;span class="o">=&lt;/span>&lt;span class="m">3&lt;/span> -a &lt;span class="nv">sharpness&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">3&lt;/span> -y &lt;span class="m">420&lt;/span> --jobs &lt;span class="m">10&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --ignore-exif --ignore-xmp &lt;span class="nv">$file&lt;/span> &lt;span class="si">${&lt;/span>&lt;span class="nv">file&lt;/span>&lt;span class="p">%*.*&lt;/span>&lt;span class="si">}&lt;/span>.avif&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">done&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>图片部分，堂堂结束！&lt;/p>
&lt;h2 id="视频部分">视频部分
&lt;/h2>&lt;p>那么…… &lt;strong>AV1 or HEVC?&lt;/strong>&lt;/p>
&lt;p>&lt;del>会出现这个问题本质上还是因为自己没有 N卡，不然直接硬件加速上AV1解决一切问题（&lt;/del>&lt;br>
当然，看标题就已经能够得出结论了：最后选了AV1。&lt;/p>
&lt;p>&lt;strong>但为什么是 AV1 不是 HEVC？&lt;/strong>
虽然 HEVC 在 macOS + ffmpeg 上有 hevc_videotoolbox 的硬件加速，但相较于 AV1(libsvtav1) 体积反而会来的更大些（但也不至于到无法忍受的地步）;&lt;br>
且在同等画质水平(肉眼几乎无感, 姑且将其设定为SSIM ≥ 0.95)下体积表现很好。&lt;/p>
&lt;p>&lt;strong>AV1 软件编码不慢吗？&lt;/strong>
慢是慢，但是在各种魔法参数的优化下(见下文)，ffmpeg 里速度表现还可以(4.45x)，虽然没有 HEVC 硬编快(8.24x)，但也不错。&lt;br>
再加上并没有什么转码时间上的要求，AV1 在这种情况下还蛮香的。&lt;/p>
&lt;p>于是乎，AV1 成了最终选择.&lt;/p>
&lt;p>同上，脚本如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> video in *&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">do&lt;/span> ffmpeg -i &lt;span class="nv">$video&lt;/span> -c:v libsvtav1 -preset &lt;span class="m">10&lt;/span> -crf &lt;span class="m">38&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -svtav1-params input-depth&lt;span class="o">=&lt;/span>10:tune&lt;span class="o">=&lt;/span>2:enable-qm&lt;span class="o">=&lt;/span>1:qm-min&lt;span class="o">=&lt;/span>0:keyint&lt;span class="o">=&lt;/span>&lt;span class="m">300&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -c:a copy -threads &lt;span class="m">10&lt;/span> &lt;span class="si">${&lt;/span>&lt;span class="nv">video&lt;/span>&lt;span class="p">%*.*&lt;/span>&lt;span class="si">}&lt;/span>-av1.mp4&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">done&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>具体参数不再赘述，在此附上参考文章：&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://wiki.x266.mov/docs/encoders/SVT-AV1#encoding" target="_blank" rel="noopener"
>https://wiki.x266.mov/docs/encoders/SVT-AV1#encoding&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://www.ffmpeg.org/ffmpeg-all.html#libsvtav1" target="_blank" rel="noopener"
>https://www.ffmpeg.org/ffmpeg-all.html#libsvtav1&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/master/Docs/Parameters.md" target="_blank" rel="noopener"
>https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/master/Docs/Parameters.md&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>TODO: 详细的文档记录&amp;amp; benchmarks (PSNR SSIM etc.)&lt;/p>
&lt;h2 id="最终结果">最终结果
&lt;/h2>&lt;p>Cosplay 图库里的数据实在太多 根本压不完（&lt;br>
这一部分等全部搞定之后再更新（&lt;/p>
&lt;p>更新：压完嘞（&lt;br>
最后结果： 354G -&amp;gt; 64G&lt;br>
82% 的空间优化，可喜可贺可喜可贺（&lt;/p>
&lt;h2 id="技术细节视频下的-av1-编码调参">技术细节:视频下的 AV1 编码调参
&lt;/h2>&lt;p>&lt;code>ffmpeg&lt;/code> 作为老牌的音视频处理瑞士军刀，配合 SVT-AV1 ，可供调整的编码参数多了不是一点半点，搞得人晕头转向（&lt;br>
在此额外参考了 &lt;a class="link" href="https://ottverse.com/analysis-of-svt-av1-presets-and-crf-values/" target="_blank" rel="noopener"
>Comparing SVT-AV1 Presets: Size, Quality, and Speed with CRF Variations&lt;/a>，文中对 SVT-AV1 编码器在不同预设和crf下的编码性能与质量进行了实验。&lt;/p>
&lt;p>略过文中的测试方法，直接看结论：&lt;br>
编码性能（以 FPS 衡量）:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/67251/39/26337/491422/66c0a89aF1d3a7827/d9ff25216cd40b02.png.avif"
loading="lazy"
alt="在 crf 和预设不同情况下的编码速度(按照 FPS 标准)"
>&lt;/p>
&lt;p>编码质量(SSIM):&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/232809/38/24657/444827/66c0a8b1Fd050d1fa/40903af01044ebcd.png.avif"
loading="lazy"
alt="编码质量（SSIM）标准"
>&lt;br>
PSNR:&lt;br>
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/53442/8/25771/476992/66c0a8d6Fb0cfcaad/73e2f10f690ad7c3.png.avif"
loading="lazy"
alt="编码质量（PSNR）标准"
>&lt;br>
VMAF:
&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/20132/6/22579/462606/66c0a952F9af27057/d32e5fdeb9139398.png.avif"
loading="lazy"
alt="编码质量（VMAF）标准"
>&lt;/p>
&lt;p>由图可知，所使用的preset与crf (&lt;code>-preset 10 -crf 38&lt;/code>) 下,SSIM 与 PSNR 都与较低预设值和较低 crf 的对应参数区别不大，编码速度也落在了比较舒适的范围，因此使用此参数。&lt;br>
事实上，根据原文作者的结论，似乎&lt;code>-preset 12 -crf 38&lt;/code>与&lt;code>-preset 2&lt;/code>的视频参数似乎区别不大，但是速度提升了135倍，完全可以直接无脑冲……？&lt;/p>
&lt;h3 id="用数据说话">用数据说话
&lt;/h3>&lt;p>为了更贴合实际，又找了个 Cosplay 的图包里的视频进行实验:&lt;br>
实验工具:&lt;/p>
&lt;ol>
&lt;li>FFmpeg 7.0.1, built with Apple Clang version 15.0.0&lt;/li>
&lt;li>SVT-AV1 Encoder Lib v2.1.1, built with Apple LLVM 15.0.0&lt;/li>
&lt;/ol>
&lt;p>实验步骤:&lt;/p>
&lt;ol>
&lt;li>把编码的 preset 固定为 N, N∈[0,12], 步长为1&lt;/li>
&lt;li>将编码所用 crf 设置为 20~63, 步长为6&lt;/li>
&lt;li>对每个编码结果，测量 VMAF、SSIM与PSNR.&lt;/li>
&lt;/ol>
&lt;p>实验结果:&lt;/p>
&lt;script src="https://registry.npmmirror.com/chart.js/4.4.3/files/dist/chart.umd.js">&lt;/script>
&lt;script> Chart.defaults.color = '#000'; &lt;/script>&lt;div class="chart">
&lt;canvas id="41dd76e60342abb6">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('41dd76e60342abb6')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "CRF-VMAF, VMAF值",
display: true
}
}
},
data: {
labels: [
'20',
'26',
'32',
'38',
'44',
'50',
'56',
'62'
],
datasets: [
{
label:"preset-5",
data: [93.475, 93.128, 92.17, 90.777, 88.758, 86.427, 83.058, 75.349]
},
{
label:"preset-6",
data: [92.086, 92.081, 91.272, 89.904, 87.845, 85.251, 81.782, 73.534]
},
{
label:"preset-7",
data: [92.086, 92.082, 91.27, 89.9, 87.852, 85.254, 81.785, 73.539]
},
{
label:"preset-8",
data: [90.99, 91.079, 90.229, 88.937, 87.13, 84.8, 81.234, 71.915]
},
{
label:"preset-9",
data: [89.631, 89.558, 88.786, 87.568, 86.115, 83.945, 80.573, 71.412]
},
{
label:"preset-10",
data: [91.699, 90.679, 89.071, 87.069, 84.752, 82.1, 77.809, 67.244]
},
{
label:"preset-11",
data: [93.062, 91.657, 89.6, 86.905, 83.687, 80.008, 74.506, 61.702]
},
{
label:"preset-12",
data: [92.344, 90.801, 88.484, 85.689, 82.733, 79.0, 73.513, 59.816]
},
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;div class="chart">
&lt;canvas id="a66d394039da1114">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('a66d394039da1114')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "CRF-SSIM, SSIM值",
display: true
}
}
},
data: {
labels: [
'20',
'26',
'32',
'38',
'44',
'50',
'56',
'62'
],
datasets: [
{
label:"preset-5",
data: [0.994, 0.994, 0.993, 0.993, 0.992, 0.991, 0.99, 0.986]
},
{
label:"preset-6",
data: [0.994, 0.994, 0.993, 0.992, 0.992, 0.991, 0.989, 0.985]
},
{
label:"preset-7",
data: [0.994, 0.994, 0.993, 0.992, 0.992, 0.991, 0.989, 0.985]
},
{
label:"preset-8",
data: [0.993, 0.993, 0.993, 0.992, 0.991, 0.99, 0.989, 0.984]
},
{
label:"preset-9",
data: [0.993, 0.993, 0.992, 0.991, 0.991, 0.99, 0.988, 0.984]
},
{
label:"preset-10",
data: [0.993, 0.992, 0.992, 0.991, 0.99, 0.989, 0.987, 0.981]
},
{
label:"preset-11",
data: [0.993, 0.992, 0.992, 0.991, 0.989, 0.987, 0.985, 0.979]
},
{
label:"preset-12",
data: [0.993, 0.992, 0.991, 0.99, 0.989, 0.988, 0.985, 0.979]
}
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;div class="chart">
&lt;canvas id="2ffbec580c23e3c4">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('2ffbec580c23e3c4')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "CRF-PSNR, PSNR值",
display: true
}
}
},
data: {
labels: [
'20',
'26',
'32',
'38',
'44',
'50',
'56',
'62'
],
datasets: [
{
label:"preset-5",
data: [50.142, 49.879, 49.337, 48.747, 47.973, 47.195, 46.116, 44.255]
},
{
label:"preset-6",
data: [49.636, 49.536, 49.054, 48.482, 47.702, 46.88, 45.807, 43.888]
},
{
label:"preset-7",
data: [49.638, 49.531, 49.057, 48.485, 47.698, 46.879, 45.806, 43.887]
},
{
label:"preset-8",
data: [48.94, 49.02, 48.556, 48.013, 47.317, 46.568, 45.563, 43.449]
},
{
label:"preset-9",
data: [48.132, 48.231, 47.89, 47.431, 46.966, 46.29, 45.362, 43.323]
},
{
label:"preset-10",
data: [48.996, 48.629, 48.038, 47.332, 46.652, 45.889, 44.761, 42.599]
},
{
label:"preset-11",
data: [49.545, 48.923, 48.119, 47.265, 46.26, 45.334, 44.067, 41.741]
},
{
label:"preset-12",
data: [49.146, 48.475, 47.618, 46.773, 45.967, 45.085, 43.996, 41.66]
}
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;div class="chart">
&lt;canvas id="3fd26eae9b503623">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('3fd26eae9b503623')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "Preset-VMAF, VMAF值",
display: true
}
}
},
data: {
labels: [
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
],
datasets: [
{
label:"crf-20",
data: [93.475, 92.086, 92.086, 90.99, 89.631, 91.699, 93.062, 92.344]
},
{
label:"crf-26",
data: [93.128, 92.081, 92.082, 91.079, 89.558, 90.679, 91.657, 90.801]
},
{
label:"crf-32",
data: [92.17, 91.272, 91.27, 90.229, 88.786, 89.071, 89.6, 88.484]
},
{
label:"crf-38",
data: [90.777, 89.904, 89.9, 88.937, 87.568, 87.069, 86.905, 85.689]
},
{
label:"crf-44",
data: [88.758, 87.845, 87.852, 87.13, 86.115, 84.752, 83.687, 82.733]
},
{
label:"crf-50",
data: [86.427, 85.251, 85.254, 84.8, 83.945, 82.1, 80.008, 79.0]
},
{
label:"crf-56",
data: [83.058, 81.782, 81.785, 81.234, 80.573, 77.809, 74.506, 73.513]
}
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;div class="chart">
&lt;canvas id="7d1326b9e208ecab">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('7d1326b9e208ecab')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "Preset-SSIM, SSIM值",
display: true
}
}
},
data: {
labels: [
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
],
datasets: [
{
label:"crf-20",
data: [0.994, 0.994, 0.994, 0.993, 0.993, 0.993, 0.993, 0.993]
},
{
label:"crf-26",
data: [0.994, 0.994, 0.994, 0.993, 0.993, 0.992, 0.992, 0.992]
},
{
label:"crf-32",
data: [0.993, 0.993, 0.993, 0.993, 0.992, 0.992, 0.992, 0.991]
},
{
label:"crf-38",
data: [0.993, 0.992, 0.992, 0.992, 0.991, 0.991, 0.991, 0.99]
},
{
label:"crf-44",
data: [0.992, 0.992, 0.992, 0.991, 0.991, 0.99, 0.989, 0.989]
},
{
label:"crf-50",
data: [0.991, 0.991, 0.991, 0.99, 0.99, 0.989, 0.987, 0.988]
},
{
label:"crf-56",
data: [0.99, 0.989, 0.989, 0.989, 0.988, 0.987, 0.985, 0.985]
}
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;div class="chart">
&lt;canvas id="aa3ee0c3b03e35dd">&lt;/canvas>
&lt;/div>
&lt;script>
document.addEventListener('DOMContentLoaded', () => {
var ctx = document.getElementById('aa3ee0c3b03e35dd')
var options =
{
type: 'line',
options: {
plugins: {
title: {
text: "Preset-PSNR, PSNR值",
display: true
}
}
},
data: {
labels: [
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
],
datasets: [
{
label:"crf-20",
data: [50.142, 49.636, 49.638, 48.94, 48.132, 48.996, 49.545, 49.146]
},
{
label:"crf-26",
data: [49.879, 49.536, 49.531, 49.02, 48.231, 48.629, 48.923, 48.475]
},
{
label:"crf-32",
data: [49.337, 49.054, 49.057, 48.556, 47.89, 48.038, 48.119, 47.618]
},
{
label:"crf-38",
data: [48.747, 48.482, 48.485, 48.013, 47.431, 47.332, 47.265, 46.773]
},
{
label:"crf-44",
data: [47.973, 47.702, 47.698, 47.317, 46.966, 46.652, 46.26, 45.967]
},
{
label:"crf-50",
data: [47.195, 46.88, 46.879, 46.568, 46.29, 45.889, 45.334, 45.085]
},
{
label:"crf-56",
data: [46.116, 45.807, 45.806, 45.563, 45.362, 44.761, 44.067, 43.996]
}
]
},
};
new Chart(ctx, options);
});
&lt;/script>
&lt;h3 id="那么结论是">那么，结论是
&lt;/h3>&lt;p>在编码速率和编码质量来看，&lt;code>-preset 10 -crf 38&lt;/code>的参数的确符合了要求，也没有产生视觉上的瑕疵，与上文的结论一致。&lt;/p></description></item><item><title>一个野生录播man的录播站</title><link>https://baysonfox.com/2024/04/23/ddman/</link><pubDate>Tue, 23 Apr 2024 10:01:13 +0000</pubDate><guid>https://baysonfox.com/2024/04/23/ddman/</guid><description>&lt;p>之前录了很多Vtuber的直播，全部上传到了录播站，可以用侧栏的“&lt;a class="link" href="https://rec.baysonfox.com" target="_blank" rel="noopener"
>录播站&lt;/a>”访问&lt;/p>
\[2024/4/23\]&lt;p> 旧的录播数据在微软之前针对 Microsoft 365 E5 全局的清剿中不幸全部丢失，一切重新开始，部分紧急备份的数据重新上传中.&lt;/p>
&lt;p>以下为历史更新记录：
&lt;details>
&lt;summary>&lt;/summary>
\[2021/2/28\]&lt;p> Remove Ywwuyi &lt;em>(22727127-ywwuyi)&lt;/em>&lt;br>
&lt;/p>
\[2021/2/28\]&lt;p> Remove &lt;em>5086-哔哩**哔哩线下活动&lt;/em>&lt;br>
&lt;/p>
\[2021/3/8\]&lt;p> 网络不稳定，只录下了一部分&lt;br>
&lt;/p>
\[2021/4/17\]&lt;p> 数据结构调整，老存档被统一移动到ARCHIVE文件夹下&lt;br>
&lt;/p>
\[2021/4/27\]&lt;p> 录播暂时停止更新，预计在5.1恢复，届时稳定性会大大提高.&lt;br>
&lt;/p>
\[2021/5/20\]&lt;ol>
&lt;li>现在可能手动监控上传部分录像，全自动系统在做了在做了&lt;/li>
&lt;li>&lt;em>876396-进击的冰糖&lt;/em> 更名为 &lt;em>876396-冰糖IO&lt;/em> 以适应名称变化&lt;/li>
&lt;/ol>
\[2021/5/22\]&lt;p> 全自动录播系统测试中&lt;br>
&lt;/p>
\[2021/5/23\]&lt;p> 现在上传部分还是不太稳定 有时候需要手动上传&lt;br>
&lt;/p>
\[2021/5/27\]&lt;p> 这几天软路由升级 无录播 sorry 有需要的可以去上方的录播备份获取&lt;br>
&lt;/p>
\[2021/6/12\]&lt;p> 没想到啊 软路由稳定了 主路由坏了 是时候换新的服务器了&lt;br>
&lt;/p>
\[2021/6/16\]&lt;p> 服务器换了 结果睿站国外的一台服务器又有bug 难搞…… &lt;strong>暂时禁用弹幕录制+文件修复预防bug&lt;/strong>&lt;br>
&lt;/p>
\[2021/6/17\]&lt;p> Still buggy…… 上传在工作了 但是偶尔还是会遇到一些超长的上传&lt;br>
&lt;/p>
\[2021/7/17\]&lt;p> &lt;em>BUG Found&lt;/em> 每次主播一波播到第二天的时候就会上传失败翻车 原因已经定位了 就是不知道怎么修&lt;br>
&lt;/p>
\[2021/7/30\]&lt;p> 录播从22:00开始不保证录制准确 23:50后无任何录播数据，碎片严重 需要清查.&lt;br>
&lt;/p>
\[2021/8/1\]&lt;ol>
&lt;li>876396-冰糖IO* 在2021/7/29的录播 产生大量分片，无法处理，故无档&lt;/li>
&lt;li>&lt;em>3822389-有栖Mana_Official&lt;/em> 在2021/7/30的B限录播文件损坏 无法处理 无档&lt;/li>
&lt;/ol>
&lt;/details>&lt;/p>
&lt;p>&lt;img src="https://img30.360buyimg.com/img/jfs/t20270817/27609/19/22719/36161/66c0a9b5Fefd24228/aadf3ad22ffc334c.png.avif"
loading="lazy"
alt="image.png"
>&lt;/p>
&lt;p>&lt;strong>录制VTuber和VUP们仅仅是个人爱好和存档用&lt;/strong>&lt;br>
如有不妥可联系baysonfox#baysonfox.com (# -&amp;gt; @).&lt;/p></description></item><item><title>使用 Btrfs 格式的根分区启动树莓派</title><link>https://baysonfox.com/2022/07/20/boot-rpi-using-btrfs/</link><pubDate>Wed, 20 Jul 2022 22:00:47 +0800</pubDate><guid>https://baysonfox.com/2022/07/20/boot-rpi-using-btrfs/</guid><description>&lt;h2 id="重新生成-initramfs">重新生成 initramfs
&lt;/h2>&lt;p>在默认情况下，Raspberry Pi OS 的 btrfs 是支持是作为 kernel modules 存在的，需要重新生成对应的 initramfs 使内核能够挂载 btrfs 文件系统.&lt;/p>
&lt;style>[data-scheme=dark] .chroma{color:#f8f8f2;background-color:#272822}[data-scheme=dark] .chroma .err{color:#bb0064}[data-scheme=dark] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=dark] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=dark] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=dark] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=dark] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=dark] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=dark] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=dark] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=dark] .chroma .k,[data-scheme=dark] .chroma .kc,[data-scheme=dark] .chroma .kd{color:#66d9ef}[data-scheme=dark] .chroma .kn{color:#f92672}[data-scheme=dark] .chroma .kp,[data-scheme=dark] .chroma .kr,[data-scheme=dark] .chroma .kt{color:#66d9ef}[data-scheme=dark] .chroma .n{color:#f8f8f2}[data-scheme=dark] .chroma .na{color:#a6e22e}[data-scheme=dark] .chroma .nb,[data-scheme=dark] .chroma .bp{color:#f8f8f2}[data-scheme=dark] .chroma .nc{color:#a6e22e}[data-scheme=dark] .chroma .no{color:#66d9ef}[data-scheme=dark] .chroma .nd{color:#a6e22e}[data-scheme=dark] .chroma .ni{color:#f8f8f2}[data-scheme=dark] .chroma .ne,[data-scheme=dark] .chroma .nf{color:#a6e22e}[data-scheme=dark] .chroma .fm,[data-scheme=dark] .chroma .nl,[data-scheme=dark] .chroma .nn{color:#f8f8f2}[data-scheme=dark] .chroma .nx{color:#a6e22e}[data-scheme=dark] .chroma .py{color:#f8f8f2}[data-scheme=dark] .chroma .nt{color:#f92672}[data-scheme=dark] .chroma .nv,[data-scheme=dark] .chroma .vc,[data-scheme=dark] .chroma .vg,[data-scheme=dark] .chroma .vi,[data-scheme=dark] .chroma .vm{color:#f8f8f2}[data-scheme=dark] .chroma .l{color:#ae81ff}[data-scheme=dark] .chroma .ld,[data-scheme=dark] .chroma .s,[data-scheme=dark] .chroma .sa,[data-scheme=dark] .chroma .sb,[data-scheme=dark] .chroma .sc,[data-scheme=dark] .chroma .dl,[data-scheme=dark] .chroma .sd,[data-scheme=dark] .chroma .s2{color:#e6db74}[data-scheme=dark] .chroma .se{color:#ae81ff}[data-scheme=dark] .chroma .sh,[data-scheme=dark] .chroma .si,[data-scheme=dark] .chroma .sx,[data-scheme=dark] .chroma .sr,[data-scheme=dark] .chroma .s1,[data-scheme=dark] .chroma .ss{color:#e6db74}[data-scheme=dark] .chroma .m,[data-scheme=dark] .chroma .mb,[data-scheme=dark] .chroma .mf,[data-scheme=dark] .chroma .mh,[data-scheme=dark] .chroma .mi,[data-scheme=dark] .chroma .il,[data-scheme=dark] .chroma .mo{color:#ae81ff}[data-scheme=dark] .chroma .o,[data-scheme=dark] .chroma .ow{color:#f92672}[data-scheme=dark] .chroma .p{color:#f8f8f2}[data-scheme=dark] .chroma .c,[data-scheme=dark] .chroma .ch,[data-scheme=dark] .chroma .cm,[data-scheme=dark] .chroma .c1,[data-scheme=dark] .chroma .cs,[data-scheme=dark] .chroma .cp,[data-scheme=dark] .chroma .cpf{color:#75715e}[data-scheme=dark] .chroma .gd{color:#f92672}[data-scheme=dark] .chroma .ge{font-style:italic}[data-scheme=dark] .chroma .gi{color:#a6e22e}[data-scheme=dark] .chroma .gs{font-weight:700}[data-scheme=dark] .chroma .gu{color:#75715e}[data-scheme=light] .chroma{color:#272822;background-color:#fafafa}[data-scheme=light] .chroma .err{color:#960050}[data-scheme=light] .chroma .lntd{vertical-align:top;border:0;margin:0;padding:0}[data-scheme=light] .chroma .lntable{border-spacing:0;border:0;width:100%;margin:0;padding:0;display:block}[data-scheme=light] .chroma .lntable>tbody{width:100%;display:block}[data-scheme=light] .chroma .lntable>tbody>tr{width:100%;display:flex}[data-scheme=light] .chroma .lntable>tbody>tr>td:last-child{overflow-x:auto}[data-scheme=light] .chroma .hl{background-color:#ffc;width:100%;display:block}[data-scheme=light] .chroma .lnt{color:#7f7f7f;margin-right:.4em;padding:0 .4em;display:block}[data-scheme=light] .chroma .ln{color:#7f7f7f;margin-right:.4em;padding:0 .4em}[data-scheme=light] .chroma .k,[data-scheme=light] .chroma .kc,[data-scheme=light] .chroma .kd{color:#00a8c8}[data-scheme=light] .chroma .kn{color:#f92672}[data-scheme=light] .chroma .kp,[data-scheme=light] .chroma .kr,[data-scheme=light] .chroma .kt{color:#00a8c8}[data-scheme=light] .chroma .n{color:#111}[data-scheme=light] .chroma .na{color:#75af00}[data-scheme=light] .chroma .nb,[data-scheme=light] .chroma .bp{color:#111}[data-scheme=light] .chroma .nc{color:#75af00}[data-scheme=light] .chroma .no{color:#00a8c8}[data-scheme=light] .chroma .nd{color:#75af00}[data-scheme=light] .chroma .ni{color:#111}[data-scheme=light] .chroma .ne,[data-scheme=light] .chroma .nf{color:#75af00}[data-scheme=light] .chroma .fm,[data-scheme=light] .chroma .nl,[data-scheme=light] .chroma .nn{color:#111}[data-scheme=light] .chroma .nx{color:#75af00}[data-scheme=light] .chroma .py{color:#111}[data-scheme=light] .chroma .nt{color:#f92672}[data-scheme=light] .chroma .nv,[data-scheme=light] .chroma .vc,[data-scheme=light] .chroma .vg,[data-scheme=light] .chroma .vi,[data-scheme=light] .chroma .vm{color:#111}[data-scheme=light] .chroma .l{color:#ae81ff}[data-scheme=light] .chroma .ld,[data-scheme=light] .chroma .s,[data-scheme=light] .chroma .sa,[data-scheme=light] .chroma .sb,[data-scheme=light] .chroma .sc,[data-scheme=light] .chroma .dl,[data-scheme=light] .chroma .sd,[data-scheme=light] .chroma .s2{color:#d88200}[data-scheme=light] .chroma .se{color:#ae81ff}[data-scheme=light] .chroma .sh,[data-scheme=light] .chroma .si,[data-scheme=light] .chroma .sx,[data-scheme=light] .chroma .sr,[data-scheme=light] .chroma .s1,[data-scheme=light] .chroma .ss{color:#d88200}[data-scheme=light] .chroma .m,[data-scheme=light] .chroma .mb,[data-scheme=light] .chroma .mf,[data-scheme=light] .chroma .mh,[data-scheme=light] .chroma .mi,[data-scheme=light] .chroma .il,[data-scheme=light] .chroma .mo{color:#ae81ff}[data-scheme=light] .chroma .o,[data-scheme=light] .chroma .ow{color:#f92672}[data-scheme=light] .chroma .p{color:#111}[data-scheme=light] .chroma .c,[data-scheme=light] .chroma .ch,[data-scheme=light] .chroma .cm,[data-scheme=light] .chroma .c1,[data-scheme=light] .chroma .cs,[data-scheme=light] .chroma .cp,[data-scheme=light] .chroma .cpf{color:#75715e}[data-scheme=light] .chroma .gd{color:#f92672}[data-scheme=light] .chroma .ge{font-style:italic}[data-scheme=light] .chroma .gi{color:#75af00}[data-scheme=light] .chroma .gs{font-weight:700}[data-scheme=light] .chroma .gu{color:#75715e}&lt;/style>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&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="c1"># initramfs-tools 默认情况下已经安装&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install initramfs-tools btrfs-tools&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>向 &lt;code>/etc/initramfs-tools/modules&lt;/code> 中添加相应的 kernel modules :&lt;br>
&lt;code>sudo vi /etc/initramfs-tools/modules&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">btrfs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">xor
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">zlib_deflate
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">raid6_pq&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>保存后，使用 &lt;code>mkinitramfs -o /boot/initramfs-btrfs.gz&lt;/code> 生成新的 initramfs.&lt;br>
之后，修改 &lt;code>/boot/config.txt&lt;/code> 加载新的 initramfs.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo vi /boot/config.txt
&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"># For more options and informations see&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># http://rpf.io/configtxt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Some settings may impact device functionality. See link above for details&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">initramfs initramfs-btrfs.gz&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>重启设备，确认新的 initramfs 正常被加载.&lt;/p>
&lt;hr>
&lt;h2 id="将-ext4-rootfs-转换成-btrfs-格式">将 ext4 rootfs 转换成 btrfs 格式
&lt;/h2>&lt;p>在 &lt;strong>linux&lt;/strong> 下，将装有系统的 SD卡 / 硬盘链接电脑，通过 &lt;code>btrfs-convert&lt;/code> 将 rootfs 转换成 btrfs 格式，以我的硬盘为例:&lt;br>
注: /dev/sdb2 为 rootfs 分区，下文以它为例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"># 如果是SD卡，将 /dev/sda 替换成对应设备
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">root@baysonfox:~# fdisk -l /dev/sda
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Disk /dev/sdb: 465.76 GiB, 500107862016 bytes, 976773168 sectors
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Disk model:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Units: sectors of 1 * 512 = 512 bytes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sector size (logical/physical): 512 bytes / 512 bytes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">I/O size (minimum/optimal): 4096 bytes / 33553920 bytes
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Disklabel type: dos
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Disk identifier: 0x0ee3e8a8
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Device Boot Start End Sectors Size Id Type
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/dev/sdb1 8192 532479 524288 256M c W95 FAT32 (LBA)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/dev/sdb2 532480 138127359 137594880 65.6G 83 Linux
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/dev/sdb3 138127360 976773119 838645760 399.9G 83 Linux&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;ol>
&lt;li>
&lt;p>使用 &lt;code>fsck.ext4 /dev/sdb2&lt;/code> 确认分区正常&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用 &lt;code>btrfs-convert /dev/sdb2&lt;/code> 将 ext4 格式的 rootfs 转换为 btrfs 格式&lt;/p>
&lt;/li>
&lt;li>
&lt;p>挂载转换完成的 btrfs rootfs&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 挂载 rootfs 和 boot&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo mkdir /tmp/rootfs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># rootfs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo mount /dev/sdb2 /tmp/rootfs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># boot&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo mount /dev/sdb1 /tmp/rootfs/boot
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>在 rootfs 下创建 swap 子卷，并禁用 btrfs 的 CoW，存放 swap 文件&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 在树莓派 rootfs 分区下创建 ./swap 子卷存放 swap 文件 &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">cd&lt;/span> /tmp/rootfs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo btrfs subvolume create swap
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 根据 https://wiki.archlinux.org/title/btrfs#Swap_file&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo chattr +C swap/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">cd&lt;/span> swap
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo dd &lt;span class="k">if&lt;/span>&lt;span class="o">=&lt;/span>/dev/zero &lt;span class="nv">of&lt;/span>&lt;span class="o">=&lt;/span>swapfile &lt;span class="nv">bs&lt;/span>&lt;span class="o">=&lt;/span>1M &lt;span class="nv">count&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">512&lt;/span> &lt;span class="nv">status&lt;/span>&lt;span class="o">=&lt;/span>progress
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo chmod &lt;span class="m">0600&lt;/span> swapfile
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 编辑 /etc/dphys-swapfile 添加 CONF_SWAPFILE=/swap/swapfile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo vi /tmp/rootfs/etc/dphys-swapfile
&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="c1"># where we want the swapfile to be, this is the default&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">CONF_SWAPFILE&lt;/span>&lt;span class="o">=&lt;/span>/swap/swapfile
&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>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="调整挂载和系统设置">调整挂载和系统设置
&lt;/h2>&lt;ol>
&lt;li>
&lt;p>编辑 &lt;code>/tmp/rootfs/etc/fstab&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 编辑 /etc/fstab&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 将 / 的挂载条目的 ext4 改为 btrfs, 并且将最后的 0 1 改为 0 0, 禁用fsck&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo vi /tmp/rootfs/etc/fstab
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e.g. &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># PARTUUID=c469d4fc-02 / btrfs defaults,noatime 0 0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>编辑 &lt;code>/tmp/rootfs/boot/cmdline.txt&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 编辑 /boot/cmdline.txt, 将 rootfstype=ext4 改为 rootfstype=btrfs fsck.repair=yes 改为 fsck.repair=no&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo vi /tmp/rootfs/boot/cmdline.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># e.g. &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># console=serial0,115200 console=tty1 root=PARTUUID=0ee3e8a8-02 rootfstype=btrfs fsck.repair=no rootwait&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>回到树莓派，添加一段脚本，防止以后 kernel 升级后无法启动&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 参考 https://www.ephestione.it/booting-btrfs-root-partition-on-raspberri-pi/&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"> sudo vi /etc/kernel/postinst.d/btrfs-update
&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">#!/bin/bash &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> &lt;span class="s2">&amp;#34;x&lt;/span>&lt;span class="nv">$2&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> !&lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;x/boot/kernel8.img&amp;#34;&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="o">============&lt;/span> UPDATE &lt;span class="nv">INITRAMFS&lt;/span> &lt;span class="o">==============&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> mkinitramfs -o /boot/initramfs-btrfs.gz
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="o">============&lt;/span> UPDATE &lt;span class="nv">COMPLETED&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="c1"># 确保权限&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo chmod &lt;span class="m">755&lt;/span> /etc/kernel/postinst.d/btrfs-update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;li>
&lt;p>重启回到系统，重新生成 swapfile&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl"> sudo dphys-swapfile swapoff
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo dphys-swapfile uninstall
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo dphys-swapfile install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> sudo dphys-swapfile swapon
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/li>
&lt;/ol></description></item><item><title>Search</title><link>https://baysonfox.com/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://baysonfox.com/search/</guid><description/></item><item><title>归档</title><link>https://baysonfox.com/archives/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://baysonfox.com/archives/</guid><description/></item><item><title>友情链接</title><link>https://baysonfox.com/links/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://baysonfox.com/links/</guid><description/></item></channel></rss>