<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Wayne</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.zipavif.com/</id>
  <link href="https://blog.zipavif.com/" rel="alternate"/>
  <link href="https://blog.zipavif.com/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Wayne</rights>
  <subtitle>Tech blog about multimedia process</subtitle>
  <title>Wayne's Image/Video Encoding</title>
  <updated>2026-05-31T23:22:57.964Z</updated>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="AVIF" scheme="https://blog.zipavif.com/tags/AVIF/"/>
    <category term="JPEG" scheme="https://blog.zipavif.com/tags/JPEG/"/>
    <category term="CICP" scheme="https://blog.zipavif.com/tags/CICP/"/>
    <category term="ICC" scheme="https://blog.zipavif.com/tags/ICC/"/>
    <category term="Color" scheme="https://blog.zipavif.com/tags/Color/"/>
    <content>
      <![CDATA[<p>做图像处理的同学都知道色彩有 RGB，也有 YUV，图像或者视频压缩中常用的是 YUV，但显示用的是 RGB；另外在 JPEG 图片的属性中通常会看到 sRGB，在 AVIF 的图片中通常会看到 CICP 的值；这些都是什么，为什么看着简单，实际却有一些坑在，本文尝试讲清楚。</p><h2 id="颜色信息的几个维度"><a href="#颜色信息的几个维度" class="headerlink" title="颜色信息的几个维度"></a>颜色信息的几个维度</h2><p>颜色信息主要包含三个维度——color primaries、transfer characteristics、matrix coefficients——另外还有一个独立的 range 标志。</p><h3 id="Color-primaries-CP"><a href="#Color-primaries-CP" class="headerlink" title="Color primaries (CP)"></a>Color primaries (CP)</h3><p>定义这个色彩空间能表示的颜色范围（色域）。要理解 CP，先理解两个 CIE 1931 概念：</p><ul><li><strong>CIE XYZ</strong>：一个<strong>绝对的颜色空间</strong>，设备无关——一个颜色对应的 XYZ 值只取决于光谱和人眼模型，跟用什么屏幕/相机无关。不同 RGB 色彩空间之间的转换，本质上都是<strong>先转到 XYZ，再从 XYZ 转到目标空间</strong>。比如 sRGB → Display P3 走的是 sRGB → XYZ → Display P3 两步。ICC 把这个中转枢纽叫 PCS (Profile Connection Space)。</li><li><strong>CIE 1931 chromaticity diagram (xy 色度图)</strong>：那张<strong>马蹄形图</strong>，用来可视化色域。每个色彩空间（sRGB、Display P3、BT.2020）的色域是图上的一个三角形——<strong>三角形越大，能表示的颜色越多</strong>。参见 <a href="https://en.wikipedia.org/wiki/SRGB#/media/File:SRGB_chromaticity_CIE1931.svg">Wikipedia 上的 sRGB chromaticity diagram</a>。</li></ul><p><strong>CP 干的事就是在 xy 色度图上选 3 个点作为 R/G/B 原色 + 1 个点作为 white point</strong>——三角形和白点定了，色彩空间就定了。常见的 sRGB / Display P3 / BT.2020 共享 D65 white point 但 R/G/B 三角形依次变大。</p><p>一个实际的坑：<strong>色域宽不等于看得到</strong>。即使你的图片标了 Display P3，如果显示器只支持 sRGB，那超出 sRGB 三角形的颜色你也看不见——OS 的 color management 会把它们映射/clip 回 sRGB 色域。</p><h3 id="Transfer-characteristics-TC"><a href="#Transfer-characteristics-TC" class="headerlink" title="Transfer characteristics (TC)"></a>Transfer characteristics (TC)</h3><p>描述<strong>线性 RGB</strong> 和<strong>非线性 RGB</strong> 之间的映射曲线。要理解 TC，先理解这两种 RGB：</p><ul><li><strong>Linear RGB</strong>：值<strong>正比于真实光强度</strong>。相机 sensor 出来就是线性数据（光强 2x → 数字值 2x）。最典型的 linear RGB 载体就是相机 <strong>RAW 文件</strong>——sensor 经 black level / 白平衡 / demosaic 之后的原始数据，完全没有 gamma 编码，所以专业摄影/调色工作流都用 RAW，保留全部动态范围和后期调整余地。所有”真实光学”运算（blending、缩放、tone mapping 等）也必须在 linear 域做，否则不符合物理——例如在非线性域对两个像素取平均，结果会偏暗发灰，因为加权关系被曲线扭曲过。</li><li><strong>非线性 RGB</strong>：值经过 TC 编码，码字分布<strong>贴合人眼对亮度的感知</strong>。为什么需要非线性编码：人眼对暗部远比亮部敏感（近似对数响应），但 8/10-bit 是均匀离散；如果直接用 linear 存，亮部浪费一堆码字，暗部却出现明显 banding。非线性编码把有限的 bit budget 花到人眼最敏感的地方。</li></ul><p>举个例子，sRGB gamma 大致是 <code>V_非线性 ≈ V_linear^(1/2.2)</code>，这条曲线<strong>在暗部斜率陡，亮部斜率缓</strong>——linear 的暗部 <code>[0, 0.1]</code> 被”拉伸”到非线性的 <code>[0, 0.35]</code>，linear 的亮部 <code>[0.5, 1.0]</code> 反而被”压缩”到非线性的 <code>[0.73, 1.0]</code>。映射到 8-bit 量化后，linear 暗部那 10% 拿到了约 90 个码字，亮部那 50% 反而只拿到约 70 个码字——刚好和人眼敏感度分布吻合。</p><p>TC 就是这两域之间的转换曲线，有两个方向——OETF（光→电，相机端）和 EOTF（电→光，显示器端）。注意”非线性”≠”gamma”：gamma (power law) 只是一种，用于 SDR (sRGB / BT.709)；HDR 还有 PQ、HLG 等，曲线形状完全不同但都由 TC 这个维度统一描述。</p><p>工程上的典型套路：<strong>存储/传输用非线性，运算回 linear</strong>。例如 sharpyuv 在做迭代下采样时就是在 linear 域 downsample，再转回非线性域；严格说 alpha blending、image resize 都该在 linear 域做。</p><h3 id="Matrix-coefficients-MC"><a href="#Matrix-coefficients-MC" class="headerlink" title="Matrix coefficients (MC)"></a>Matrix coefficients (MC)</h3><p>YUV ↔ <strong>非线性 RGB</strong> 之间的转换矩阵——注意作用对象是 TC 编码后的非线性 RGB（SDR 下俗称 gamma RGB），不是 linear RGB。</p><p>常见 enum 值：</p><ul><li><strong>MC=1</strong>：BT.709（HDTV / 桌面视频默认）</li><li><strong>MC=5/6</strong>：BT.601（SD 标清电视 / JPEG / WebP 默认）</li><li><strong>MC=9</strong>：BT.2020-NCL（HDR / UHD 默认）</li><li><strong>MC=0</strong>：<em>Identity</em>——三个 plane 里存的不是 YUV，而是未经矩阵转换的 RGB 数据，<strong>顺序是 GBR</strong>（不是 RGB），常见于无损 RGB 编码场景（如 AVIF lossless RGB）</li></ul><p>为什么需要这么多矩阵：YUV 里 Y 是亮度，需要按人眼对 R/G/B 的敏感度做加权（绿权重最大、蓝最小），不同标准的加权系数不同——BT.601 沿用模拟电视时代的系数，BT.709 重新测量后修正，BT.2020 因色域扩大再次调整。<strong>同一份 YUV 数据用错矩阵解码会出现色偏</strong>，这也是为什么 CICP 必须把 MC 显式写出来。</p><h3 id="Range"><a href="#Range" class="headerlink" title="Range"></a>Range</h3><p>YUV 的数值范围。full range 是 <code>[0, 255]</code>，limited range 是 <code>[16, 235]</code>，把 16 当全黑、235 当全白；<code>[0,16]</code> 和 <code>[235,255]</code> 是 headroom / footroom——历史上源于模拟视频时代给信号 overshoot/undershoot 留的余量（”blacker than black” / “whiter than white”），现代数字 codec (H.264 / H.265 / AV1) 沿用了这个约定，余量同时用来吸收编码过程中的 ringing 类 overshoot，最后在 RGB 域统一 clip。JPEG 用 full range，WebP / H.26x / AV1 默认 limited range——所以不能直接把 WebP 解出来的 YUV 平面塞给 JPEG 编码器，必须先转回 RGB（比如经 PNG 中转）。</p><h2 id="两套描述体系：ICC-与-CICP"><a href="#两套描述体系：ICC-与-CICP" class="headerlink" title="两套描述体系：ICC 与 CICP"></a>两套描述体系：ICC 与 CICP</h2><p>描述这套信息有两套体系，并不是新老替代关系，而是各自主导不同的生态：</p><ul><li><strong>ICC profile</strong>（International Color Consortium）：表达力强、格式灵活，主导图像与印刷工作流；JPEG / PNG / AVIF 都可以携带 ICC profile。</li><li><strong>CICP</strong>（Coding-Independent Code Points）：ITU-T H.273 定义的三元组 <code>(CP/TC/MC)</code>，每个值都是查表的 enum，紧凑且自描述，主导视频和新一代 codec 生态。</li></ul><p>引用 libavif wiki 对三者的精确定义：</p><blockquote><p>CP defines a specific set of color primaries with a single enumerated value from Table 2 of H.273.<br>TC defines a transfer function with a single enumerated value from Table 3 of H.273.<br>MC defines a specific set of matrix coefficients as a single enumerated value from Table 4 of H.273.</p></blockquote><p>一个常见坑：CICP 的三个值在 AVIF 文件中按 <code>CP/TC/MC</code> 顺序存储，但 <code>ffprobe</code> 输出时是 <code>MC/CP/TC</code>（MC 被挪到最前），抄数的时候很容易搞错。</p><p>AVIF 同时支持 CICP 和 ICC。<strong>如果文件携带了 ICC profile，它会覆盖 CP 和 TC</strong>（用 ICC 作为 RGB 颜色空间的 source of truth），<strong>但 MC 不被覆盖</strong>——因为 MC 描述的是编码前 YUV↔RGB 的转换方式，跟 ICC 描述的 RGB 色彩空间是正交的两件事。</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://github.com/AOMediaCodec/libavif/wiki/CICP">https://github.com/AOMediaCodec/libavif/wiki/CICP</a> — libavif 关于 CICP 的解释</li><li><a href="https://www.color.org/iccprofile.xalter">https://www.color.org/iccprofile.xalter</a> — ICC 官方对 ICC profile 的介绍</li><li><a href="https://www.itu.int/rec/T-REC-H.273">https://www.itu.int/rec/T-REC-H.273</a> — ITU-T H.273 原规范，CICP 三张表的 source of truth</li><li><a href="https://wangwei1237.github.io/2022/08/14/Why-so-much-color-space-in-video/">https://wangwei1237.github.io/2022/08/14/Why-so-much-color-space-in-video/</a> — 视频色彩空间的图文讲解</li><li><a href="https://en.wikipedia.org/wiki/SRGB">https://en.wikipedia.org/wiki/SRGB</a> — sRGB 与 CIE 1931 chromaticity diagram 可视化</li></ul>]]>
    </content>
    <id>https://blog.zipavif.com/2026/05/31/Color-CICP-vs-ICC/</id>
    <link href="https://blog.zipavif.com/2026/05/31/Color-CICP-vs-ICC/"/>
    <published>2026-05-31T06:00:00.000Z</published>
    <summary>
      <![CDATA[<p>做图像处理的同学都知道色彩有 RGB，也有 YUV，图像或者视频压缩中常用的是 YUV，但显示用的是 RGB；另外在 JPEG 图片的属性中通常会看到 sRGB，在 AVIF 的图片中通常会看到 CICP]]>
    </summary>
    <title>图像的颜色信息：sRGB、CICP 与那些转换的坑</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="AI" scheme="https://blog.zipavif.com/categories/AI/"/>
    <category term="Cursor" scheme="https://blog.zipavif.com/tags/Cursor/"/>
    <category term="AI" scheme="https://blog.zipavif.com/tags/AI/"/>
    <category term="AI-Code-Plugin" scheme="https://blog.zipavif.com/tags/AI-Code-Plugin/"/>
    <content>
      <![CDATA[<h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><p>之前一直想尝试Cursor，有各种事情耽搁没做，正好周末有时间，把Cursor装起来体验了一番。因为我之前已经比较频繁使用AI代码插件，这次正好一起对比下；我之前主要是使用VS Code的Continue，多用于写一些小的脚本，发现插件使用起来效果也都不错。这次对比，主要是针对更复杂和更高级的任务，看哪一个表现更好；</p><p>先说结论，Cursor的使用体验确实要好过AI插件一大截，基本上是0和1的区别；<br>我的测试方法如下，找一个开源的项目，问一些全局的，高层的问题，看哪个回答的更好；我选用的代码库是libaom，它是AV1的编码器，非常复杂；很适合测试这个任务；对于Cursor，使用的大模型是Sonet 3.5，</p><h2 id="问题设计"><a href="#问题设计" class="headerlink" title="问题设计"></a>问题设计</h2><p>我问了一下三个问题:</p><ol><li>Which function is the entry points for partition search?</li><li>哪一个文件主要用于做global motion的搜索？</li><li>哪一个文件用来控制不同的速度档次下打开或者关闭某些快速算法？<br>可以看到，这三个问题是非常high-level的问题，并且我没有给出具体的Context，所以要靠Cursor或者Continue插件自己来建立合适的Context；</li></ol><h2 id="Cursor"><a href="#Cursor" class="headerlink" title="Cursor"></a>Cursor</h2><p>对于问题1，Cursor的回答如下:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">Let me search through the codebase to find the entry points for partition search in AV1.</span><br><span class="line"> **Search codebase for &quot;partition serach entry point cuntion av1 encoder&quot;. No results found**</span><br><span class="line"> Let me try a more specific search using grep to find partition-related functions.    </span><br><span class="line"> **Grepped codebase for &quot;rd_pick_partition&quot;**</span><br><span class="line"></span><br><span class="line">Based on the search results, I can identify the main entry points for partition search in AV1. There are two primary functions:</span><br><span class="line"></span><br><span class="line">1. av1_rd_pick_partition() - This is the main rate-distortion (RD) based partition search function, located in partition_search.c. This is used when RD optimization is enabled.</span><br><span class="line"></span><br><span class="line">2. av1_nonrd_pick_partition() - This is the non-RD based partition search function, also in partition_search.c. This is a faster version used when RD optimization is disabled.</span><br><span class="line"></span><br><span class="line">Let me get more details about these functions to provide you with a better understanding.</span><br><span class="line"> **Read partition_search.c L5457-5674**</span><br><span class="line"> The main entry point is av1_rd_pick_partition() in partition_search.c. This function performs a thorough rate-distortion optimization to find the best partition structure. It&#x27;s used when quality is prioritized over encoding speed. The function signature is:</span><br></pre></td></tr></table></figure><br>其中**中间的内容是Cursor执行的动作，从这里面可以看到，Cursor会做对应的代码搜索，找到相关的内容，给出进一步的解释；这里面Cursor搜索的结果非常令人吃惊，因为我并没有给出具体的函数名字，例如rd_pick_partition，而是近似的名字”partition search”，他还是准确找到了相关的函数；</p><p>对于问题2， Cursor的回答如下:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">让我帮你找一下与global motion搜索相关的文件。</span><br><span class="line">**Searched codebase for &quot;global motion search&quot;.**</span><br><span class="line">根据搜索结果，我可以看到主要用于global motion搜索的文件是av1/encoder/global_motion_facade.c。这个文件包含了全局运动估计的主要实现。让我解释一下关键部分：</span><br></pre></td></tr></table></figure><br>同样，Cursor精确地找到了相关的文件，并给出了对应的解释；</p><p>对于问题3，Cursor的回答如下:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">让我搜索一下与速度档次和算法控制相关的代码</span><br><span class="line">** Searched codebase for &quot;speed settings control algorithm enabled disable&quot; **</span><br><span class="line">根据搜索结果,我发现在 av1/encoder/speed_features.h 和 av1/encoder/speed_features.c 中定义了控制不同速度档次下算法开关的代码。主要的控制结构如下:</span><br><span class="line"></span><br><span class="line">在 speed_features.h 中定义了多个结构体来组织不同类型的速度特性:</span><br><span class="line">HIGH_LEVEL_SPEED_FEATURES: 高层速度特性</span><br><span class="line">FIRST_PASS_SPEED_FEATURES: 第一遍编码的速度特性</span><br><span class="line">PARTITION_SPEED_FEATURES: 分区相关的速度特性</span><br><span class="line">MV_SPEED_FEATURES: 运动估计相关的速度特性</span><br><span class="line">INTER_MODE_SPEED_FEATURES: 帧间预测模式相关的速度特性</span><br><span class="line">INTERP_FILTER_SPEED_FEATURES: 插值滤波器相关的速度特性</span><br><span class="line">INTRA_MODE_SPEED_FEATURES: 帧内预测模式相关的速度特性</span><br></pre></td></tr></table></figure><br>可以看到Cursor不仅找到了对应的问题，而且把相关的文件和结构体都列出来做了总结；</p><h2 id="Continue-dev"><a href="#Continue-dev" class="headerlink" title="Continue.dev:"></a>Continue.dev:</h2><p>使用同样的Claude 3.7 Sonnet的模型，问了同样的问题，只是我在chat 中手动添加了@codebase，希望能给一些提示；但等了很久没有反馈，一直显示”Generating”;</p><p>之后我尝试选择”Agent” mode，还是同样的结果；<br>我检查CPU使用率，发现VS Code确实有在运行，我怀疑是在database中做矢量搜索，可能本地检索太慢，一直没有返回相关的context给大模型做生成；</p><p>我也有尝试使用本地Ollama的模型，但本地模型context比较有限(qwen3大概40k)，非常容易超出context的限制；</p><h2 id="Aidar"><a href="#Aidar" class="headerlink" title="Aidar"></a>Aidar</h2><p>Aidar有去使用repo map，根据tree sitter会对整个代码库做解析，理论上应该会更好；让我们来试下：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">export ANTHROPIC_API_KEY=xxx</span><br><span class="line">aider --model anthropic/claude-3-5-sonnet-latest</span><br><span class="line"># Enter the command line of aider</span><br><span class="line">/chat-mode ask</span><br><span class="line">Which function is the entry points for partition search?</span><br></pre></td></tr></table></figure></p><p>Aidar的动作是:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">**Update repo-map**</span><br><span class="line">From the files shown so far, I cannot definitively determine the main entry point for partition search. While I can see</span><br><span class="line">references to partition-related code like partition_search_type and variance_partition_alloc(), the actual partition search entry</span><br><span class="line">point is likely in files that haven&#x27;t been shared yet.</span><br><span class="line"></span><br></pre></td></tr></table></figure></p><p>有意思的是，Aidar会持续要求加入一些新的context，例如一些文件，但看起来最终没有找到相关的函数；<br>看起来即使有repo map，但Aidar的能力也还是要差不少。</p>]]>
    </content>
    <id>https://blog.zipavif.com/2025/05/18/Cursor-VS-AI-Code-Assist-Plugin/</id>
    <link href="https://blog.zipavif.com/2025/05/18/Cursor-VS-AI-Code-Assist-Plugin/"/>
    <published>2025-05-18T12:47:34.000Z</published>
    <summary>
      <![CDATA[<h2 id="Introduction"><a href="#Introduction" class="headerlink"]]>
    </summary>
    <title>Cursor与AI插件在复杂任务下的对比</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="AI" scheme="https://blog.zipavif.com/categories/AI/"/>
    <category term="RAG" scheme="https://blog.zipavif.com/tags/RAG/"/>
    <category term="LLM" scheme="https://blog.zipavif.com/tags/LLM/"/>
    <content>
      <![CDATA[<h2 id="What-is-RAG"><a href="#What-is-RAG" class="headerlink" title="What is RAG?"></a>What is RAG?</h2><p>RAG stands for Retrieve-Augmented Generation, a technique that enhances the capabilities of language models by incorporating external information. Compared to pure Language Models (LLMs), RAG offers several advantages:</p><ol><li><strong>More Precise Answers</strong>: By retrieving relevant information from a knowledge base, RAG can provide more accurate and contextually appropriate responses.</li><li><strong>Reduced Hallucinations</strong>: RAG reduces the likelihood of generating false or irrelevant information by grounding its outputs in real-world data.</li><li><strong>Access to Latest Information</strong>: RAG can utilize up-to-date external sources, ensuring that the generated content is current.</li></ol><h2 id="RAG-Structure"><a href="#RAG-Structure" class="headerlink" title="RAG Structure"></a>RAG Structure</h2><p>The typical structure of a RAG system includes:</p><ol><li><strong>Vector Database</strong>: This stores the knowledge base as vectors for efficient retrieval.</li><li><strong>Embedding Model</strong>: Converts text from the knowledge base into vector representations.</li><li><strong>Language Model (LLM)</strong>: Generates responses based on retrieved context and its own understanding.</li></ol><h2 id="RAG-Process"><a href="#RAG-Process" class="headerlink" title="RAG Process"></a>RAG Process</h2><p>The process of RAG involves two main steps:</p><ol><li><strong>Indexing</strong>: The knowledge base is indexed using an embedding model, converting textual information into vectors for storage in a vector database.</li><li><strong>Query and Response Generation</strong>: When a query is received, the system retrieves relevant context from the vector database and uses it to generate a response with the help of the LLM.</li></ol><h2 id="Open-Source-Solutions"><a href="#Open-Source-Solutions" class="headerlink" title="Open-Source Solutions"></a>Open-Source Solutions</h2><p>Several open-source frameworks are available for implementing RAG:</p><ol><li><strong>LLamaIndex</strong>: Connects to various data sources and converts data into vectors using an embedding model.</li><li><strong>HayStack</strong></li><li><strong>LangChain</strong></li><li><strong>GraphRAG</strong>: A logic reasoning framework that supports multi-hop fact questions.</li><li><strong>KAG</strong>: An OpenSPG engine-based framework for building domain-specific knowledge bases.</li><li><strong>AnythingLLM</strong>: Provides a chat interface to convert documents into context for LLMs.</li><li><strong>MaxKB</strong>: An open-source knowledge base问答系统 used in customer service, internal knowledge bases, and education.</li><li><strong>RAGFlow</strong>: A deep document understanding-based RAG engine that provides reliable Q&amp;A services.</li><li><strong>FastGPT</strong>: A knowledge base问答 system with data processing and model calling capabilities.</li><li><strong>Langchain-Chatchat</strong>: Local knowledge base Q&amp;A based on Langchain and ChatGLM.</li><li><strong>FlashRAG</strong>: A Python toolset for reproducing and developing RAG research, including 36 preprocessed benchmark datasets and 15 advanced algorithms.</li><li>Open WebUI（前身为Ollama WebUI）是一个可扩展的、功能丰富的、用户友好的自托管Web界面，设计用于完全离线运行。它支持各种LLM（大型语言模型）运行器，包括Ollama和兼容OpenAI的API。</li></ol><h3 id="Vector-Database"><a href="#Vector-Database" class="headerlink" title="Vector Database"></a>Vector Database</h3><ul><li><strong>Qdrant</strong>: A fast, Rust-based vector database focusing on performance and efficiency.</li><li><strong>Chroma</strong>: Popular for its simplicity and ease of use.</li></ul><h3 id="Embedding-Model"><a href="#Embedding-Model" class="headerlink" title="Embedding Model"></a>Embedding Model</h3><ul><li><strong>Sentence Transformers</strong>: A library for generating high-quality sentence embeddings.</li><li><strong>BERT (Bidirectional Encoder Representations from Transformers)</strong>: BERT is a transformer-based model known for its ability to understand context by pre-training on a large corpus of text.</li></ul><h3 id="Language-Models-LLMs"><a href="#Language-Models-LLMs" class="headerlink" title="Language Models (LLMs)"></a>Language Models (LLMs)</h3><ul><li><strong>llama3.3</strong></li><li><strong>Gemma2</strong></li></ul><h3 id="Cloud-Solutions"><a href="#Cloud-Solutions" class="headerlink" title="Cloud Solutions"></a>Cloud Solutions</h3><p>Cloud-based services that support RAG include:</p><ul><li><strong>Google Vertex AI Matching Engine</strong>: Provides vector search and a managed RAG solution for enterprise search.</li><li><strong>AWS Kendra + Sagemaker/Bedrock</strong>: Combines with Kendra for enterprise search and Bedrock for LLMs to build RAG solutions.</li><li><strong>Azure AI Search + Azure OpenAI Service</strong>: Offers vector search and integrates well with Azure OpenAI Service for building RAG applications.</li><li><strong>火山方舟大模型服务平台</strong>: A platform for large language models.</li><li><strong>腾讯云ES</strong>: Based on the ElasticSearch ecosystem.</li><li><strong>阿里云PAI</strong>: Guide to deploying a RAG-based dialogue system.</li></ul><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://www.volcengine.com/docs/82379/1263276">火山方舟大模型服务平台</a><br><a href="https://help.aliyun.com/zh/pai/user-guide/deploy-a-rag-based-dialogue-system">Learn how to deploy a RAG-based dialogue system on Aliyun PAI</a><br><a href="https://cloud.tencent.com/developer/article/2426551">详解几种常见本地大模型个人知识库工具部署、微调及对比选型</a><br><a href="https://bbs.huaweicloud.com/blogs/440805">RAG框架总结主流框架推荐</a><br><a href="https://blog.mthreads.com/blog/AI/2024-11-01-rag/">搭建个人 RAG 推理服务</a>    </p>]]>
    </content>
    <id>https://blog.zipavif.com/2025/01/01/RAG-in-2024/</id>
    <link href="https://blog.zipavif.com/2025/01/01/RAG-in-2024/"/>
    <published>2025-01-01T15:00:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="What-is-RAG"><a href="#What-is-RAG" class="headerlink" title="What is RAG?"></a>What is RAG?</h2><p>RAG stands for]]>
    </summary>
    <title>Introduction to RAG</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="AI" scheme="https://blog.zipavif.com/categories/AI/"/>
    <category term="Tools" scheme="https://blog.zipavif.com/categories/AI/Tools/"/>
    <category term="AI" scheme="https://blog.zipavif.com/tags/AI/"/>
    <category term="Obsidian" scheme="https://blog.zipavif.com/tags/Obsidian/"/>
    <category term="Notion" scheme="https://blog.zipavif.com/tags/Notion/"/>
    <category term="Copilot" scheme="https://blog.zipavif.com/tags/Copilot/"/>
    <content>
      <![CDATA[<p>作为一个程序员，日常记录和内容创作是必不可少的。我也曾尝试过多种笔记工具，但都未能完全满足我的需求。Notion虽然比Evernote更强大，但在将笔记转化为内容方面仍显得有些繁琐。近年来，AI辅助写作逐渐兴起，但我对Notion AI的体验并不满意，尤其是它的收费模式。直到有一天，我偶然发现了Obsidian——一款真正让我爱不释手的神器。</p><h3 id="博客发表"><a href="#博客发表" class="headerlink" title="博客发表"></a>博客发表</h3><p>我的博客采用Hexo框架，文章以Markdown格式保存于<code>_source</code>目录中。而Obsidian同样支持Markdown格式，因此两者无缝对接，无需额外转换。</p><h4 id="自动化部署"><a href="#自动化部署" class="headerlink" title="自动化部署"></a>自动化部署</h4><p>目前，我将博客托管在GitHub上，并使用Cloudflare进行静态网站托管。在Cloudflare上设置跟踪master分支后，一旦有更新，便会自动构建网站并进行更新。</p><p><strong>操作步骤：</strong></p><ol><li>使用ln命令将网站的<code>_source</code>目录软连接到Obsidian的vault中：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln -s /my/website/_source blogs</span><br></pre></td></tr></table></figure></li><li>编辑完博客后，通过右上角的<code>move file to</code>功能将其移动至<code>blog</code>目录。</li><li>通过git提交更改。</li></ol><p><strong>注意：</strong> 博客头部需添加metadata，否则可能出现问题。以下是一个示例格式：<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: Hello World</span><br><span class="line">date: 2025-01-01</span><br><span class="line">tags:</span><br><span class="line">  - Test</span><br><span class="line">categories:</span><br><span class="line">  - Debug</span><br><span class="line">---</span><br></pre></td></tr></table></figure></p><h3 id="AI辅助写作"><a href="#AI辅助写作" class="headerlink" title="AI辅助写作"></a>AI辅助写作</h3><p>为了进一步提升写作效率，我安装了<code>Copilot</code>插件。该插件支持多种模型，既可以是云服务，也可以是本地通过Ollama提供的。</p><p><strong>配置方法</strong>：</p><p>打开Copilot的setting，选择<code>Add Custom Model</code>, 输入模型的名字，例如<code>qwen2.5:32b</code>，模型的名字可以通过在服务器端使用<code>ollama list</code>获得；<code>Provider</code>选择Ollama，填入<code>Base URL</code>，例如<code>http://localhost:11434</code>. 如果是在远程服务器上部署的ollama，则可以通过端口转发来在本地建立服务<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -L 11434:localhost:11434 -fNT remoteserver -o IdentitiesOnly=yes -q -A -T</span><br></pre></td></tr></table></figure></p><p><strong>使用方法：</strong></p><ol><li>配置完成后，通过<code>Cmd + P</code>打开命令面板。</li><li>选择<code>Copilot: Open Copilot Chat Window</code>，默认会在Sidebar中显示chat窗口。</li><li>特别之处在于，你可以通过<code>[[</code>选项引用note，将其作为context进行写作，极大地提高了效率。</li></ol><hr><p>Obsidian不仅是一款优秀的笔记工具，更是一个强大的AI辅助写作平台。它让我在编程之余，也能轻松地分享我的知识和经验。如果你也是一位程序员，不妨试试这款神器吧！</p>]]>
    </content>
    <id>https://blog.zipavif.com/2025/01/01/Obsidian-best-note-app/</id>
    <link href="https://blog.zipavif.com/2025/01/01/Obsidian-best-note-app/"/>
    <published>2025-01-01T15:00:00.000Z</published>
    <summary>
      <![CDATA[<p>作为一个程序员，日常记录和内容创作是必不可少的。我也曾尝试过多种笔记工具，但都未能完全满足我的需求。Notion虽然比Evernote更强大，但在将笔记转化为内容方面仍显得有些繁琐。近年来，AI辅助写作逐渐兴起，但我对Notion]]>
    </summary>
    <title>Obsidian：程序猿的神器，助你高效写作与分享</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Technology" scheme="https://blog.zipavif.com/categories/Technology/"/>
    <category term="LLM" scheme="https://blog.zipavif.com/tags/LLM/"/>
    <category term="Blogging" scheme="https://blog.zipavif.com/tags/Blogging/"/>
    <category term="Obsidian" scheme="https://blog.zipavif.com/tags/Obsidian/"/>
    <category term="Ollama" scheme="https://blog.zipavif.com/tags/Ollama/"/>
    <content>
      <![CDATA[<p>Ollama是在个人PC上运行大模型的一个推理软件，使用简单，适合新手。</p><h2 id="Ollama安装"><a href="#Ollama安装" class="headerlink" title="Ollama安装"></a>Ollama安装</h2><p>打开终端，运行<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -fsSL https://ollama.com/install.sh | sh</span><br></pre></td></tr></table></figure><br>国内访问比较慢，需要使用代理；</p><h2 id="如何使用"><a href="#如何使用" class="headerlink" title="如何使用"></a>如何使用</h2><p>本地使用的时候，需要先运行<code>ollama serve</code>打开服务，然后再运行某一个模型，例如<code>ollama run llama3.3</code>，Ollama会先去拉取llama3.3，之后再去运行，会给出下面的对话框:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$: ollama run llama3.3</span><br><span class="line">&gt;&gt;&gt; Send a message (/? for help)</span><br></pre></td></tr></table></figure></p><p>不同模型占用的显存不一样，可以通过<code>ollama ps</code>来查看目前模型运行的情况:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~$ ollama ps</span><br><span class="line">NAME               ID              SIZE     PROCESSOR          UNTIL</span><br><span class="line">llama3.3:latest    a6eb4748fd29    45 GB    46%/54% CPU/GPU    4 minutes from now</span><br></pre></td></tr></table></figure><br>可以看到模型有54%是跑在GPU上，46%跑在CPU上。</p><p>也可以通过<code>ollama list</code>来查看目前有哪些模型<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">~$ ollama list</span><br><span class="line">NAME                        ID              SIZE      MODIFIED</span><br><span class="line">qwen2.5:32b                 9f13ba1299af    19 GB     7 days ago</span><br><span class="line">llava:latest                8dd30f6b0cb1    4.7 GB    10 days ago</span><br><span class="line">codegemma:latest            0c96700aaada    5.0 GB    10 days ago</span><br><span class="line">internlm2:20b               a864ac8dade2    11 GB     10 days ago</span><br><span class="line">internlm2:latest            5050e36678ab    4.5 GB    10 days ago</span><br><span class="line">glm4:latest                 5b699761eca5    5.5 GB    10 days ago</span><br><span class="line">deepseek-coder-v2:latest    63fb193b3a9b    8.9 GB    12 days ago</span><br><span class="line">wizardcoder:latest          de9d848c1323    3.8 GB    12 days ago</span><br></pre></td></tr></table></figure></p><h2 id="作为服务运行"><a href="#作为服务运行" class="headerlink" title="作为服务运行"></a>作为服务运行</h2><p>有时候会把Ollama作为一个服务运行，这样可以免除每次都执行<code>ollama server</code>的操作；可以通过一下方式实现:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl edit ollama.service</span><br></pre></td></tr></table></figure><br>添加以下内容<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># [Service] </span><br><span class="line"># Environment=&quot;OLLAMA_HOST=0.0.0.0&quot;</span><br></pre></td></tr></table></figure><br>通过指定HOST为0.0.0.0，这样局域网内其他机器也可访问。<br>之后再运行下面命令<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl daemon-reload </span><br><span class="line">sudo systemctl restart ollama </span><br><span class="line">sudo systemctl status ollama.service</span><br></pre></td></tr></table></figure><br>如果系统显示下面信息，则说明ollama正常运行了:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">● ollama.service - Ollama Service </span><br><span class="line">Loaded: loaded (/etc/systemd/system/ollama.service; enabled; vendor preset: enabled) </span><br><span class="line">Drop-In: /etc/systemd/system/ollama.service.d </span><br><span class="line">         └─override.conf </span><br><span class="line">Active: active (running) since Fri 2024-12-20 07:40:24 CST; 6min ago </span><br><span class="line">Main PID: 1241 (ollama) </span><br><span class="line">Tasks: 15 (limit: 37306) </span><br><span class="line">Memory: 139.7M </span><br><span class="line">CGroup: /system.slice/ollama.service </span><br><span class="line">        └─1241 /usr/local/bin/ollama serve</span><br></pre></td></tr></table></figure></p><h2 id="Troubleshoot"><a href="#Troubleshoot" class="headerlink" title="Troubleshoot"></a>Troubleshoot</h2><ol><li>Ubuntu系统自动升级后发现Ollama运行很慢，通过<code>ollama ps</code>发现推理都在CPU上面进行；再运行<code>nvidia-smi</code>，发现找不到显卡；通过以下手段进行修复：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># Secondly, you can find your NVIDIA driver&#x27;s version by following command </span><br><span class="line">ls /usr/src | grep nvidia </span><br><span class="line"># 3.Lastly, you should install the corresponding version by following command sudo apt install dkms </span><br><span class="line">sudo dkms install -m nvidia -v xxx </span><br><span class="line"># https://stackoverflow.com/questions/67071101/nvidia-smi-has-failed-because-it-couldnt-communicate-with-the-nvidia-driver-mak</span><br></pre></td></tr></table></figure></li><li>很多插件(VSCode中的Continue)都使用本地的Ollama，如果Ollama设置在服务端，需要通过端口映射来建立本地的Ollama服务<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -L 11434:localhost:11434 -fNT remoteserver -o IdentitiesOnly=yes -q -A -T</span><br></pre></td></tr></table></figure></li></ol>]]>
    </content>
    <id>https://blog.zipavif.com/2025/01/01/Ollama-Introduction/</id>
    <link href="https://blog.zipavif.com/2025/01/01/Ollama-Introduction/"/>
    <published>2025-01-01T09:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Ollama是在个人PC上运行大模型的一个推理软件，使用简单，适合新手。</p>
<h2 id="Ollama安装"><a href="#Ollama安装" class="headerlink"]]>
    </summary>
    <title>Introduce to Ollama</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="Rate Control" scheme="https://blog.zipavif.com/tags/Rate-Control/"/>
    <category term="Encoder" scheme="https://blog.zipavif.com/tags/Encoder/"/>
    <content>
      <![CDATA[<h2 id="VBV的原理"><a href="#VBV的原理" class="headerlink" title="VBV的原理"></a>VBV的原理</h2><p>Video Buffer Verifier是编码器内部的一个模块，用来确保解码器可以smooth播放视频。通常会假设decoder内部有一块buffer，专门用于缓冲输入码流，这块buffer的size是固定的。我们先考虑下解码端的情况，再来看下反推到编码端是怎么样的</p><p>解码端是从网络/CD中读入码流，读入的速度可以是固定的，也可以是变化的，我们先考虑固定的情况。假如$R<em>{dec}^{in}$是解码器读入码流的速度，解码器把码流存储在码流Buffer中，Buffer的size是$S</em>{buf}$，另外一方面，当Buffer中的数据够一帧的数据时，解码器就会把整帧的数据一次性消耗掉。</p><p>理论上来说，当Buffer中没有空间来缓存数据时，这种情况就叫Buffer Overflow，这种情况是可能是因为$R<em>{dec}^{out}$太小导致; 另外一种情况是，当Buffer中没有数据的时候，就叫Buffer Underflow。这种情况是$R</em>{dec}^{out}$太快，大于$R_{dec}^{in}$，导致没有数据；</p><p>以上是解码端的情况，VBV本身就是模拟下解码端的情况，从而来确保编码端的码流符合规范；$R<em>{enc}^{in}$代表送给编码端VBV的速率，$R</em>{enc}^{out}$代表从VBV流出的码率；注意<br>$R<em>{enc}^{out} = R</em>{dec}^{in},\<br>R<em>{enc}^{in} = R</em>{dec}^{out}$</p><p>因此，当$R<em>{enc}^{in} &gt; R</em>{enc}^{out}$时，对应的是$R<em>{dec}^{out} &gt; R</em>{dec}^{int}$，也就是码流比较高的时候，会导致Buffer underflow;</p><p>当$R<em>{enc}^{in} &lt; R</em>{enc}^{out}$是，对应解码器端 $R<em>{dec}^{in} &lt; R</em>{dec}^{out}$，也就是实际编码码率较低的时候，会导致Buffer overflow.</p><p>以上就是vbv的基本原理，以下介绍下264/265里面的设置。</p><h2 id="X264’s-VBV-setting"><a href="#X264’s-VBV-setting" class="headerlink" title="X264’s VBV setting"></a>X264’s VBV setting</h2><p>—vbv-maxrate: </p><p>Maximum local bitrate (kbits/sec). Will be used only if vbv-bufsize is also non-zero. Both vbv-bufsize and vbv-maxrate are required to enable VBV in CRF mode. Default 0 (disabled)</p><p>—vbv-bufsize:<br>Specify the size of the VBV buffer (kbits). Enables VBV in ABR mode. In CRF mode, <a href="https://x265.readthedocs.io/en/master/cli.html#cmdoption-vbv-maxrate"><strong><code>--vbv-maxrate</code></strong></a> must also be specified. Default 0 (vbv disabled)</p><p>—vbv-init:</p><p>Initial buffer occupancy. The portion of the decode buffer which must be full before the decoder will begin decoding. Determines absolute maximum frame size. May be specified as a fractional value between 0 and 1, or in kbits. In other words, these two option pairs are equivalent:</p><p>vbv-bufsize / vbv-maxrate代表了缓冲几秒的视频；</p><p>—vbv-end:</p><p>Final buffer fullness. The portion of the decode buffer that must be full after all the specified frames have been inserted into the decode buffer. </p><p>—min-vbv-fullness</p><p>Minimum VBV fullness percentage to be maintained. Specified as a fractional value ranging between 0 and 100. Default 50 i.e, Tries to keep the buffer at least 50% full at any point in time.</p><p>Decreasing the minimum required fullness shall improve the compression efficiency, but is expected to affect VBV conformance. Experimental option.</p><p>—max-vbv-fullness</p><p>Maximum VBV fullness percentage to be maintained. Specified as a fractional value ranging between 0 and 100. Default 80 i.e Tries to keep the buffer at max 80% full at any point in time.</p><p><strong>Increasing the minimum required fullness shall improve the compression efficiency,</strong></p><p>m_bufferFillFinal: 代表了已经填充的buffer(因为在模拟解码端的处理？)，也就相等于编码器端的可用空间</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Initial</span></span><br><span class="line"><span class="keyword">if</span> (m_param-&gt;rc.vbvBufferInit &gt; <span class="number">1.</span>)</span><br><span class="line">    m_param-&gt;rc.vbvBufferInit = x265_clip3(<span class="number">0.0</span>, <span class="number">1.0</span>, m_param-&gt;rc.vbvBufferInit / m_param-&gt;rc.vbvBufferSize);</span><br><span class="line"><span class="keyword">if</span> (m_param-&gt;vbvBufferEnd &gt; <span class="number">1.</span>)</span><br><span class="line">    m_param-&gt;vbvBufferEnd = x265_clip3(<span class="number">0.0</span>, <span class="number">1.0</span>, m_param-&gt;vbvBufferEnd / m_param-&gt;rc.vbvBufferSize);</span><br><span class="line"><span class="keyword">if</span> (m_param-&gt;vbvEndFrameAdjust &gt; <span class="number">1.</span>)</span><br><span class="line">    m_param-&gt;vbvEndFrameAdjust = x265_clip3(<span class="number">0.0</span>, <span class="number">1.0</span>, m_param-&gt;vbvEndFrameAdjust);</span><br><span class="line"></span><br><span class="line">m_param-&gt;rc.vbvBufferInit = x265_clip3(<span class="number">0.0</span>, <span class="number">1.0</span>, X265_MAX(m_param-&gt;rc.vbvBufferInit, m_bufferRate / m_bufferSize));</span><br><span class="line">m_bufferFillFinal = m_bufferSize * m_param-&gt;rc.vbvBufferInit;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Update</span></span><br><span class="line">m_bufferFillFinal -= frame_bits;</span><br><span class="line">m_bufferFillFinal += rce-&gt;bufferRate;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="AV1"><a href="#AV1" class="headerlink" title="AV1"></a>AV1</h2><p>rc→starting_buffer_level: 代表了已经填充的Buffer(从解码器的角度来看)，相当于编码端的可用空间；</p><p>rc→buffer_level: 代表了已经填充Buffer（从解码端的角度来看),从编码器的角度来看，代表了可用的buffer空间</p><p>正常对它的处理如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Initialize</span></span><br><span class="line">p_rc-&gt;starting_buffer_level = starting * bandwidth / <span class="number">1000</span>;</span><br><span class="line"><span class="keyword">if</span> (p_rc-&gt;starting_buffer_level &gt;= p_rc-&gt;maximum_buffer_size) &#123;</span><br><span class="line">  p_rc-&gt;starting_buffer_level = p_rc-&gt;maximum_buffer_size * init_level / <span class="number">1000</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">rc-&gt;buffer_level = p_rc-&gt;starting_buffer_level;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Update, </span></span><br><span class="line"><span class="type">int64_t</span> new_buffer_lvl = rc-&gt;buffer_level - rc-&gt;projected_frame_size;</span><br><span class="line"><span class="keyword">if</span> (cpi-&gt;common.show_frame) new_buffer_lvl += rc-&gt;avg_frame_bandwidth;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Initialize:</p><h2 id="对VBV的一些疑问"><a href="#对VBV的一些疑问" class="headerlink" title="对VBV的一些疑问"></a>对VBV的一些疑问</h2><ol><li>VBV假设$R_{dec}^{in}$是固定的，这个假设是对的吗？一般对于VCD/DVD/Blu.ray来说，可能需要读取fixed bitrate，而此时这个假设是可以；如果没有这个限制，譬如说live streaming，此时读取的内容就是发送的数据，发送的数据即使少于码率，也不会有Buffer Overflow发生。</li><li><p>In video streaming， buffer overflow是不大会出现，可以忽略。这是因为不可能出现解码器的输入码率不可能大于解码器消耗的码率。因为输入码率是等于$Min(bandwidth, R_{enc}^{out})$，</p><p> 而$R<em>{enc}^{out} =R</em>{dec}^{out}$，因此必然会有$R<em>{dec}^{in}  ≤ R</em>{dec}^{out}$。</p></li></ol><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://www.youtube.com/watch?v=-Q7BuSXdO_8&amp;ab_channel=Demuxed">https://www.youtube.com/watch?v=-Q7BuSXdO_8&amp;ab_channel=Demuxed</a></p>]]>
    </content>
    <id>https://blog.zipavif.com/2024/11/24/VBV_intro/</id>
    <link href="https://blog.zipavif.com/2024/11/24/VBV_intro/"/>
    <published>2024-11-24T03:18:34.000Z</published>
    <summary>
      <![CDATA[<h2 id="VBV的原理"><a href="#VBV的原理" class="headerlink" title="VBV的原理"></a>VBV的原理</h2><p>Video Buffer]]>
    </summary>
    <title>Introduce to VBV</title>
    <updated>2026-05-31T23:22:57.965Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="SSIM" scheme="https://blog.zipavif.com/tags/SSIM/"/>
    <content>
      <![CDATA[<p>SSIM 是2004年提出来的，<a href="https://www.cns.nyu.edu/pub/lcv/wang03-preprint.pdf">原始论文</a>在这里。SSIM相较PSNR更符合人眼的主观感觉，因此在很多图片视频任务中广泛使用，包括压缩，降噪等等。本文简单介绍下SSIM公式，并根据论文<a href="https://ece.uwaterloo.ca/~z70wang/publications/TIP_SSIM_MathProperties.pdf">On the Mathematical Properties of the SSIM</a>对SSIM做了分析，最后总结了如何在编码器中针对SSIM来做优化。</p><h2 id="SSIM简介"><a href="#SSIM简介" class="headerlink" title="SSIM简介"></a>SSIM简介</h2><p>SSIM的计算公式如下：</p><script type="math/tex; mode=display">S(x, y) = f(l(x, y), c(x, y), s(x, y))</script><p>其中l(x, y)代表x, y对于mean的相似度，c(x, y)代表的contrast的对比度，s(x, y)代表的是结构的相似度；他们的计算方式分别如下</p><script type="math/tex; mode=display">l(x, y)=\frac {2\mu_x \mu_y + C_1} {\mu_x^2 + \mu_y^2 + C_1}</script><p>其中$\mu_x$, $\mu_y$ 分别为块的均值；其中$\mu_x$, $\mu_y$相差越大，$l(x, y)$就越小；</p><p>而对比度相似度c(x, y)的计算方式与l(x, y)的相似，具体如下</p><script type="math/tex; mode=display">c(x, y) = \frac{2\sigma_x\sigma_y + C_2}{\sigma_x^2+\sigma_y^2 + C_2}</script><p>结构相似度s(x, y)无法表示成一个数，作者是把他转换成归一化的向量，然后计算下余弦相似度:</p><script type="math/tex; mode=display">s(x, y) = \frac{\sigma_{xy}  + C_3}{\sigma_x\sigma_y + C_3}</script><p>其中$\sigma_{xy}$为x, y的covariance，expected value of the product of their deriations from there individual expected values. 计算方式为</p><script type="math/tex; mode=display">\sigma_{xy} = \frac{1}{N-1}\sum_{i=1}^N(x_i - \mu_x)(y_i - \mu_y)</script><p>也就是两个相对于均值一起变动的节奏或者波形是否一致。可以考虑一维的情况，协方差在计算的时候会减去均值。</p><p>如果$C_3  = C_2/2$，最终的SSIM的公式为</p><script type="math/tex; mode=display">SSIM(x, y) = \frac{(2\mu_x\mu_y + C1)(2\sigma_{xy} + C_2)}{(\mu_x^2 + \mu_y^2 + C_1)(\sigma_x^2 + \sigma_y^2 + C_2)}</script><p>因此SSIM(x, y) 小于1， 大于-1；</p><h2 id="On-the-Mathematical-Properties-of-the-SSIM"><a href="#On-the-Mathematical-Properties-of-the-SSIM" class="headerlink" title="On the Mathematical Properties of the SSIM"></a>On the Mathematical Properties of the SSIM</h2><p>作者首先把SSIM分成两部分，</p><script type="math/tex; mode=display">S_1(x,y) = l(x,y) = \frac{2\mu_x\mu_y + C_1}{\mu_x^2 + \mu_y^2 + C_1} \\S_2(x,y) = \frac{2\sigma_{xy} + C_2}{\sigma_x^2 + \sigma_y^2 + C_2}</script><p>然后使用$d_1 = \sqrt{1 - S_1}$和$d_2 = \sqrt{1 - S_2}$作为normalized metrics; 作者先证明了NRMSE是一个metrics，然后说明$d_1$和$d_2$是NRMSE的一种。NRMSE的定义如下</p><script type="math/tex; mode=display">NRMSE(x,y,c) = \frac{||x-y||_2}{\sqrt{||x||_2 + ||y||_2 + c}}</script><p>之后通过构建$D_2 := ||d(x,y)||_2 = \sqrt{2 - S_1(x,y) - S_2(x, y)}$来表示一个距离，$||d(x,y)||_2$是$\sqrt{1-SSIM(x,y)}$的低阶近似。</p><p>在图片或者视频的很多处理中，大部分时候mean都是保持一致的，因此SSIM中的$c(x,y)$和$s(x,y)$更加重要。作者也通过计算SSIM和$D_2$的相关性，可以看出图像的均值相差不大的情况下，SSIM和其他$D_2$的相关性是很高的，大于0.967；</p><h2 id="如何针对SSIM做优化"><a href="#如何针对SSIM做优化" class="headerlink" title="如何针对SSIM做优化"></a>如何针对SSIM做优化</h2><p>从以上分析可以看到，SSIM可以近似表示为$d_2$，$d_2$可以理解为相对损失，因此相同的SSIM分数下，复杂的块，也就是$\sigma_x$ 更大的块，可以允许有更大的损失。也可以把SSIM理解为weighted MSE，加权的因子是$\frac{1}{\sigma_x}$，因此简单的块有更大的权重。在图片或视频压缩中，可以针对简单区域分配更多的比特从而优化SSIM的表现。</p>]]>
    </content>
    <id>https://blog.zipavif.com/2024/07/28/SSIM-intra/</id>
    <link href="https://blog.zipavif.com/2024/07/28/SSIM-intra/"/>
    <published>2024-07-28T09:10:27.000Z</published>
    <summary>
      <![CDATA[<p>SSIM 是2004年提出来的，<a]]>
    </summary>
    <title>SSIM Introduction</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="IQA" scheme="https://blog.zipavif.com/tags/IQA/"/>
    <content>
      <![CDATA[<h1 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h1><p>图像压缩属于图片处理的一种，经过处理后的图片，文件体积一般会变小。</p><p>图像压缩分为无损压缩和有损压缩，无损压缩对质量没有影响，压缩率比较低；而有损压缩则通过牺牲一定的质量，达到更高的压缩率。一般压缩比越高，体积越小，质量越差。</p><p>因此在评测质量的时候，分为客观评测和主观评测。其中客观评测是指用一些算法来对图像打分，而主观评测则是人眼对图像质量进行打分。毫无疑问，主观质量评测费时费力，而且不同人评测的结果不一样，包含了很多噪声。同时，主观评测无法给出精度很高的分数，只能给出一个粗略的分数；而客观质量与主观质量相反，精准度高，容易计算，但客观质量指标的缺点是他和主观不一定吻合，目前也没有完美的客观指标；</p><p>图片的内容千奇百遍，不同场景下的内容特征会差异很大。因此在评测的时候需要根据自己的需要选择出代表图片来，使用这些图片来做评测；</p><p>图像压缩通常情况下会涉及比较复杂的操作，一般都比较费时，在比较的时候需要考虑到耗时这个因素；因此在评判一个压缩算法，除了需要考虑质量和体积，还需要考虑耗时。</p><h2 id="Test-set"><a href="#Test-set" class="headerlink" title="Test-set"></a>Test-set</h2><p>在评测的时候，需要先选定测试集，可以使用公开的测试集，也可以使用自己定制的测试集。以下是几个测试集可供选择</p><p><a href="https://cloudinary.com/labs/cid22">Cloudinary CID22</a></p><p><a href="https://www.epfl.ch/labs/mmspg/downloads/jpeg-aic3-dataset/">JPEG AIC-3</a></p><p><a href="https://drive.google.com/drive/folders/1VK12pBFnYJzJRD1k8uo38yammO-_XtkO">Kodak &amp; CLIC</a></p><h1 id="客观评测"><a href="#客观评测" class="headerlink" title="客观评测"></a>客观评测</h1><p>针对图片的客观指标是一个很活跃的研究领域，每年都会有新的客观指标出来。常用的客观指标有PSNR, SSIM, VMAF.SSIM, DSSIM, ssimara 2, VMAF。</p><h3 id="PSNR"><a href="#PSNR" class="headerlink" title="PSNR"></a>PSNR</h3><p>PSNR是pixel-level的指标，它会对比两张图片中每个像素的差异并加权平均。PSNR没有考虑人眼视觉模型，和主观不能很好的吻合，但计算简单。</p><p>后面基于PSNR开发了HVS-PSNR，WPSNR和XPSNR，其中WPSNR在计算的时候对每个块赋值一个权重，最终的PSNR是一个加权的PSNR.</p><h3 id="SSIM"><a href="#SSIM" class="headerlink" title="SSIM"></a>SSIM</h3><p>SSIM是2004年提出的，它同时考虑了均值，对比度和结构信息，比PSNR更符合人眼的主观。SSIM的具体公式如下:</p><p>$SSIM(x, y) = \frac{(2\mu<em>x\mu_y + C1)(2\sigma</em>{xy} + C_2)}{(\mu_x^2 + \mu_y^2 + C_1)(\sigma_x^2 + \sigma_y^2 + C_2)}$</p><p>基于SSIM也有很多变体，包括MS-SSIM，DSSIM等</p><p>SSIM考虑到了人眼视觉效应，对平坦区域的失真更加敏感，这和人的主观是吻合的。</p><h3 id="VMAF"><a href="#VMAF" class="headerlink" title="VMAF"></a>VMAF</h3><p>VMAF是由Netflix提出来的，内部计算了多个指标，如Visual Quality Fidelity(VIF), Detail Loss Measure(DLM) 以及Temporal Information(TI)，最终采用机器学习(SVM)的方式对多个指标进行融合得到最终的分数。VMAF与主观相关性较高，在业界内被广泛使用。</p><p>VMAF相关的模型有VMAF-Neg(VMAF-Non-enahncement-gain)，</p><h1 id="主观评测"><a href="#主观评测" class="headerlink" title="主观评测"></a>主观评测</h1><p>主观评测主要由人员做主观打分，并对打分后做统计分析，目前主流的评测方法都是基于ITU-R BT.500来做的.</p><p>一般使用Double Stimulus Continuous Quality Scale的方式进行评测，评测的时候把原图和测试图并排放置，并随机打乱顺序，由观看者对两幅图片进行打分，分值是5分制，分别表示Excellent, Good, Fair, Poor and Bad. 因此这是一种全参考的设置方式。</p><p>还有种常见的主观评测是GSB(Good:Same:Bad)评价，适合于两个编码器对比分析；</p><p>除此以外，还可以采用以下几种方式:</p><p>ACR(Absolute Category Rating): 每次评估一个视频，对视频打分; 量级分为(Bad, Poor, Faire, Good, Excellent)</p><p>DCR(Differential Comparison Rating): 每次评估一对视频(源视频，处理后视频)，对处理后视频相对于源视频的差异进行打分；(Imperceptible, Perceptible but not annoying, Slightly annoying, Annoying, very annoying)</p><p>PC/CCR: 每次评估一对视频(都是处理后的视频，对比两者的处理效果)，给出哪个视频更好的打分；打分的量级分为(Much worse, worse, slightly worse, the same, slightly better, Better, Much Better)</p><p>打分之后一般使用MOS(Mean Opinion Score)或者DMOS(Differential Mean Opinion Score)来统计出分数来；MOS常用与ACR，分数越高，质量越好；而DMOS常用于DCR，分数越低，代表与原视频越接近).</p><p>打完分之后需要做统计分析(ANOVA, T-Test)，判断下观察到的差异是因为质量变化还是因为随机的改变；另外可以检查和客观指标的吻合度，同时分析对于不同的subgroup的表现如何。</p><h1 id="速度对比"><a href="#速度对比" class="headerlink" title="速度对比"></a>速度对比</h1><p>可以计算编码/解码所用时间，内存占用率等来判断下编码器的速度；</p><h1 id="不同Codec的对比"><a href="#不同Codec的对比" class="headerlink" title="不同Codec的对比"></a>不同Codec的对比</h1><p>因为编码器在不同质量等级下生成图片的质量和大小都不一样，如果只跑出一个数据来，因为质量和体积都不一样，无法直接比较。工业界常用的方式是使用多个质量等级编码出多个数据(≥ 4)，然后计算出对应的质量和体积，最后计算BD-Rate。例如有两个JPEG编码器A和B，其中A是anchor编码器，B是测试编码器。计算BD-Rate的时候，可以用A和B跑出四个质量等级的码流，分别计算码流对应的码率和质量，最后计算BD-Rate，如果BD-Rate为正值，如3%，可以解释为要达到同样的客观指标，B要比A多用3%的码率，也就是B的压缩率更低。如果BD-Rate为负值，如-10%，则说明B要比A少用10的码率，即B的压缩率更低。</p><p>注意计算BD-Rate的时候，需要考虑到选用的客观指标和质量等级，这些需要和实际场景中的匹配上。BD-Rate的介绍可以参考<a href="https://zipavif.com/2024/07/06/BDRate/">How to use BD-Rate to evaluate codecs</a>。</p><p>评测框架可以参考<a href="https://github.com/webmproject/codec-compare">WebM codec-compare</a></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>图片压缩的评测并不简单，中间有很多的坑，在实践中需要选好测试集，并交叉对比主观评测的结果和客观评测的结果，作为一个参考。在涉及多个codec的时候，可以采用BD-Rate来比较两个Codec。</p>]]>
    </content>
    <id>https://blog.zipavif.com/2024/07/28/How.to.evaluate.Lossy.image.compression/</id>
    <link href="https://blog.zipavif.com/2024/07/28/How.to.evaluate.Lossy.image.compression/"/>
    <published>2024-07-28T08:27:27.000Z</published>
    <summary>
      <![CDATA[<h1 id="Introduction"><a href="#Introduction" class="headerlink"]]>
    </summary>
    <title>How to evaluate Lossy image compression</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="BDRate" scheme="https://blog.zipavif.com/tags/BDRate/"/>
    <content>
      <![CDATA[<h1 id="BD-BR计算和注意事项"><a href="#BD-BR计算和注意事项" class="headerlink" title="BD-BR计算和注意事项"></a>BD-BR计算和注意事项</h1><p>在视频压缩领域，常常需要比较不同算法或者不同编码器的优劣，而评价一个编码器很重要的一个指标是压缩率。计算压缩率需要比较质量和码率，相同画质下码率越低，压缩率越高；或者相同码率下，质量越高，压缩率也越高。</p><p>在实际比较的时候，因为很多的编码算法会同时影响质量和码率，导致码率或者质量无法卡齐，不好直接对比压缩率。在这种情况下就需要BD-Rate这个工具。</p><p>BD-BR全称是<strong>Bjontegaard delta bitrate (BD-BR) ，与2001年提出来的。它</strong>可以定量比较不同编码器的压缩性能，这些年一直被广泛用于编码器的评测；它主要是通过计算两条RD曲线上之间的差距来度量不同编码器的优劣，具体可以参见下图:</p><p><img src="/images/bdrate_image.png" alt="Figure1"></p><p>R-D曲线的X轴是码率，Y轴是客观指标。计算的时候可以计算R-D曲线针对X轴的积分(BD-PSNR)，也可以计算R-D曲线对于Y轴的积分(BD-Rate)；BD-PSNR可以认为是delta psnr，因此正值代表了画质提升；BD-Rate可以认为是delta rate，因此负值代表了码率节省。这里重点说明下BD-Rate.</p><h2 id="计算方式"><a href="#计算方式" class="headerlink" title="计算方式"></a>计算方式</h2><p>假如要评测两个编码器A和B的压缩率，衡量质量的标准使用PSNR；在计算BD-Rate之前，需要先使用4个或更多个码率点来进行编码，例如2Mbps, 2.5Mbps, 3Mbps和4Mbps，编码完成后统计对应4个码率点的码率和质量(PSNR);</p><ol><li>对码率先做对数变换，这个主要是为了防止不同质量等级下码率差异太大，导致高码率对整个的计算影响太大; </li></ol><script type="math/tex; mode=display">r = log_{10}R</script><ol><li>使用interpolation函数拟合出两条Rate-Distortion曲线，X轴是Rate，Y轴是PSNR; 例如$r = a + b <em> D + c </em> D^2 + d*D^3$</li><li>计算两条曲线对于Y轴积分的差，积分的时候只对Distortion有重叠的区域做积分；因此需要先计算出$D<em>{high}$和$D</em>{low}$ </li><li>对Distortion部分做normalize，也就是除以$D<em>{high} - D</em>{low}$</li><li>最后再通过幂函数恢复到原来的域</li></ol><p>最后的整个公式就是</p><script type="math/tex; mode=display">\Delta R =10^{\frac{1}{D_{high} - D_{low}} \int_{D_{low}}^{D_{high}} (r_b - r_a)dD}</script><p>以下是Netflix开源的bdrate计算脚本: <a href="https://github.com/Netflix/vmaf/tree/master/python/vmaf/tools">https://github.com/Netflix/vmaf/tree/master/python/vmaf/tools</a></p><h1 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h1><p>虽然BD-Rate对应着码率节省，但实际计算的时候BD-Rate并不等于码率节省的比例。</p><p>另外BD-Rate有单调性的假设，也就是质量会随着码率升高而升高。</p><p>一般来说，0.5db提升等同于-10%的BD-Rate；</p>]]>
    </content>
    <id>https://blog.zipavif.com/2024/07/06/BDRate/</id>
    <link href="https://blog.zipavif.com/2024/07/06/BDRate/"/>
    <published>2024-07-06T22:05:27.000Z</published>
    <summary>
      <![CDATA[<h1 id="BD-BR计算和注意事项"><a href="#BD-BR计算和注意事项" class="headerlink"]]>
    </summary>
    <title>How to use BD-Rate to evaluate codecs</title>
    <updated>2026-05-31T23:22:57.964Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="hexo" scheme="https://blog.zipavif.com/tags/hexo/"/>
    <content>
      <![CDATA[<p>Mermaid是用文本来描述Diagram，因为博客使用了hexo和Next，所以尝试在把Mermaid用起来，可以编写一些代码流程；</p><ol><li>Install Mermaid: <code>$ npm install hexo-filter-mermaid-diagrams</code></li><li>Modify Next config, like _config.next.yml，把mermaid打开。<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># Mermaid tag</span><br><span class="line">mermaid:</span><br><span class="line">  enable: true</span><br><span class="line">  # Available themes: default | dark | forest | neutral</span><br><span class="line">  theme:</span><br><span class="line">    light: default</span><br><span class="line">    dark: dark</span><br></pre></td></tr></table></figure></li><li>Modify hexo config, _confg.yml:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">highlight:</span><br><span class="line">  exclude_languages:</span><br><span class="line">    - mermaid</span><br></pre></td></tr></table></figure></li><li>Start to create diagram using Mermaid syntax, like</li></ol><pre class="mermaid">graph TDA[Hard] -->|Text| B(Round)B --> C{Decision}C -->|One| D[Result 1]C -->|Two| E[Result 2]</pre>]]>
    </content>
    <id>https://blog.zipavif.com/2023/10/25/hexo-Mermaid/</id>
    <link href="https://blog.zipavif.com/2023/10/25/hexo-Mermaid/"/>
    <published>2023-10-25T15:02:25.000Z</published>
    <summary>
      <![CDATA[<p>Mermaid是用文本来描述Diagram，因为博客使用了hexo和Next，所以尝试在把Mermaid用起来，可以编写一些代码流程；</p>
<ol>
<li>Install Mermaid: <code>$ npm install]]>
    </summary>
    <title>Using Mermaid in hexo</title>
    <updated>2026-05-31T23:22:57.965Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Multimedia" scheme="https://blog.zipavif.com/categories/Multimedia/"/>
    <category term="webp" scheme="https://blog.zipavif.com/tags/webp/"/>
    <category term="Image Encoder" scheme="https://blog.zipavif.com/tags/Image-Encoder/"/>
    <content>
      <![CDATA[<h2 id="What-is-Webp"><a href="#What-is-Webp" class="headerlink" title="What is Webp?"></a>What is Webp?</h2><p>Webp是一种图像格式，支持单张图片，动图；<br>什么平台支持？<br>如何使用？</p><h2 id="Open-Source-projects"><a href="#Open-Source-projects" class="headerlink" title="Open-Source projects"></a>Open-Source projects</h2><p>libwebp: <a href="https://chromium.googlesource.com/webm/libwebp">https://chromium.googlesource.com/webm/libwebp</a><br>mirror: <a href="https://github.com/webmproject/libwebp/">https://github.com/webmproject/libwebp/</a>    </p><h2 id="User-Guide"><a href="#User-Guide" class="headerlink" title="User Guide"></a>User Guide</h2><h3 id="Options"><a href="#Options" class="headerlink" title="Options"></a>Options</h3><ol><li>q: 指定quality factor</li><li>alpha_q: 指定透明通道的压缩率</li><li>preset: 指定图片的type</li><li>-z: 指定lossless压缩的效率</li><li>m: 压缩的速度档次，0最快，6是最慢</li><li>segment: 指定要使用的segments，默认是4</li><li>-size: 指定目标size (in bytes)</li><li>-psnr: 指定目标的PSNR</li><li>-sns: spatial noise shaping, important</li><li>-f: filter strength, default 60，是指loop filter的强度</li><li>-sharpness: filter sharpness, 0: most sharp, 7: 最小sharp</li><li>-strong: use strong filter</li><li>-sharp_yuv: use sharper RGB-&gt;YUV的转换</li><li>-partition_limit</li><li>-pass: analysis pass number</li><li>-qrange，指定最小和最大QP的范围</li><li>-mt: 使用multi-threading</li><li>-alpha_method: 指定透明通道压缩的方法</li><li>-alpha_filter: predictive filtering for alpha plane</li><li>-exact: preserve RGB value in transparent area; 也就是不修改完全透明区域的</li><li>-noalpha: 丢掉alpha的特征</li><li>-lossless: 无损压缩图像</li><li>-near_lossless: use near-lossless image preprocessing</li><li>-hint: 指定图片的特征或者提示；</li><li>-af: using autoaf，指标是ssim</li></ol><h3 id="如何把其他图片转换成Webp"><a href="#如何把其他图片转换成Webp" class="headerlink" title="如何把其他图片转换成Webp?"></a>如何把其他图片转换成Webp?</h3><p>JPG format<br>YUVJ420: YUV420P with JPEG color-range” (i.e. pixels use 0-255 range instead of 16-235 range, where 0 instead of 16 is black, and 255 instead of 235 is white);</p><p>使用工具<code>cwebp</code>，最简单的使用就是:<br><code>cwebp input.png -q 80 -o output.webp</code></p><h3 id="重要的参数"><a href="#重要的参数" class="headerlink" title="重要的参数"></a>重要的参数</h3><p>重要的参数包括<code>-preset -sns -f -m</code>:<br><code>-preset</code>: 用于指定content的类型，应该最先被设置，这样后续的设置就在这个基础上来修改; 编码器内部会根据<code>preset</code>去调整<code>sns_strength</code>, <code>filter_sharpness</code>, <code>filter_strength</code>和<code>preprocessing</code>.<br><code>-f</code>: 对应的是编码器内部的in-loop filter的filter strength;<br><code>-m</code>: 用来指定编码速度，[0, 6]，0最快，6最慢，default是4<br><code>-sns</code>: 用来打开一些visual optimization，主要用来调节bit allocation. 用来把easy part的bit分配给hard part。通常升高sns，会导致文件增大，质量变好；   </p><h4 id="sns"><a href="#sns" class="headerlink" title="sns"></a>sns</h4><p>method &gt;= 4: distortion会包括spectural distortion<br>Distortion: 在method &gt; 4的时候，会有distortion和spectral distortion<br>设置segment的时候，可以控制幅度。<br>控制uv<em>ac，越小的话，dq_uv_ac变大，和dq_uv_dc，越大,uv_dc boost的越多<br>It will set do_search</em></p><p>how to calculate alpha:<br>Do transform, collect coefficients stats, find last_none_zero and max_values;<br>alpha = last_non_zero/max_value</p><ol><li>计算每个mb的alpha<br>原理：<br>TX: 4x4<br>convert coefficients to bins，calculate the histogram of abs(level)<br>max<em>value: 出现系数最多的系数的出现次数，越大，说明0系数的越多，说明能量越少<br>last_non_zero: 最后一个非零系数，越大，说明高频的能量越多，<br>alpha = ALPHA_SCALE * last_non</em>+zero / max_value;<br>best_alpha = MAX_ALPHA - (3 * best_alpha + best_uv_alpha + 2) &gt;&gt; 2<br>高能量:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">MBAnalyze:323 analyze mbx 0, mby 1</span><br><span class="line">mode 0, last_nonzero_count 31, max_value 95</span><br><span class="line">mode 1, last_nonzero_count 31, max_value 88</span><br><span class="line">MBAnalyze:330 best_alpha 179</span><br><span class="line">MBAnalyze:341 mbx 0, mby 1, alpha 57, uv_alpha 255</span><br></pre></td></tr></table></figure>低能量：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">MBAnalyze:323 analyze mbx 0, mby 3</span><br><span class="line">mode 0, last_nonzero_count 11, max_value 234</span><br><span class="line">mode 1, last_nonzero_count 4, max_value 244</span><br><span class="line">MBAnalyze:330 best_alpha 23</span><br><span class="line">MBAnalyze:341 mbx 0, mby 3, alpha 234, uv_alpha 16</span><br></pre></td></tr></table></figure>alpha越大，Q越小；<br>beta</li></ol><h4 id="filter-params"><a href="#filter-params" class="headerlink" title="filter params"></a>filter params</h4><p>Decoder perspective:<br>9.4 Loop Filter Type and Levels<br>frame-level loop filter params:</p><ol><li>filter_type: normal or simple, simple filter only applied to luma edges;    </li><li>loop_filter_level: defines the threshold, if the different is below this threshold, it should be filtered, otherwise, it should not be changed. Usually the level correlated to quantizer levels.    </li><li>sharpness_level, constant over the frame,<br>如果loop_filter_level=0，那么应该跳过loop_filter;<br>Differences in excess of a threshold(associated to the loop_filter_level) are assumed to not being modified.      </li></ol><p>mode_ref_lf_delta_update=1, allow per-macroblock adjustment, through delta; There are two types of delta values, one for reference frame-based adjustment, and the other group is for mode-based adjustment.    </p><p>Filter header to write into  bitstreams:<br>simple:<br>level: 对应fstrength_<br>sharpness</p><p>sharpness设置越大，fstrength越大；<br>Q越大，fstrength越大；</p><p>fstrength是针对segment来的；</p><p>lf_delta</p><p>process;<br>base<em>strength = F(q, sharpness)<br>strength = 5 <em> filter_strength </em> base_strength / *(256 + beta</em>)<br>level0 = fstrength_</p><p>只filter 4x4的块，不filter 16x16和skip的块；</p><p>How to decide the strength for each segments?</p><p>Why VP8StoreFilterStats? 存储不同的delta<em>q下，do filter之后的ssim并存储起来；<br>How to decide final strength</em>;<br>VP8AdjustFilterStrength</p><h2 id="Internal-Process"><a href="#Internal-Process" class="headerlink" title="Internal Process"></a>Internal Process</h2><h3 id="Speed-0-1"><a href="#Speed-0-1" class="headerlink" title="Speed 0/1"></a>Speed 0/1</h3><h3 id="Speed-2-6"><a href="#Speed-2-6" class="headerlink" title="Speed 2~6"></a>Speed 2~6</h3><h3 id="Alpha-Encoding"><a href="#Alpha-Encoding" class="headerlink" title="Alpha Encoding"></a>Alpha Encoding</h3><p>主要通过一下几个接口来处理</p><ol><li>VP8EncInitAlpha</li><li>VP8EncStartAlpha</li><li>VP8EncFinishAlpha</li><li>VP8EncDeleteAlpha</li></ol><pre class="mermaid">graph TD;    A-->B;    A-->C;    B-->D;    C-->D;</pre><p>主要调用<code>EncodeAlpha</code>进行处理</p><h2 id="Feature"><a href="#Feature" class="headerlink" title="Feature"></a>Feature</h2><h3 id="Specify-target-size-target-PSNR"><a href="#Specify-target-size-target-PSNR" class="headerlink" title="Specify target_size/target_PSNR"></a>Specify target_size/target_PSNR</h3><p>sns: </p><h3 id="Region-based-quantization"><a href="#Region-based-quantization" class="headerlink" title="Region-based quantization"></a>Region-based quantization</h3><h3 id="Adaptive-Loop-filter"><a href="#Adaptive-Loop-filter" class="headerlink" title="Adaptive Loop-filter"></a>Adaptive Loop-filter</h3><p>根据prediction mode或参考帧来决定loop filter strength<br>Adjustment of loop-filter stregnth for each segment.</p><h3 id="RDO"><a href="#RDO" class="headerlink" title="RDO"></a>RDO</h3><h3 id="Preprocessing"><a href="#Preprocessing" class="headerlink" title="Preprocessing"></a>Preprocessing</h3><h4 id="sharp-YUV"><a href="#sharp-YUV" class="headerlink" title="sharp YUV"></a>sharp YUV</h4><p>This is applied when converting RGB to YUV</p><h4 id="Smooth-segment"><a href="#Smooth-segment" class="headerlink" title="Smooth segment"></a>Smooth segment</h4><h4 id="pseudo-random-dithering-log2"><a href="#pseudo-random-dithering-log2" class="headerlink" title="pseudo-random dithering log2"></a>pseudo-random dithering log2</h4><h4 id="Alpha-cleanup"><a href="#Alpha-cleanup" class="headerlink" title="Alpha cleanup"></a>Alpha cleanup</h4><h3 id="Lossless"><a href="#Lossless" class="headerlink" title="Lossless"></a>Lossless</h3><p>主要通过调用WebPEncodeLosslessRGB，内部是调用<code>EncodeLossless</code>.<br><code>VP8LEncodeImage</code> is used to encoding lossless.<br>内部调用<code>VP8LEncodeStream</code><br>QuantizeLevels<br>VP8FiltersInit<br>ApplyFiltersAndEncode<br>EncodeAlphaInternal —-&gt; EncodeLossless —-&gt; VP8LEncodeStream</p><h3 id="Segment"><a href="#Segment" class="headerlink" title="Segment"></a>Segment</h3><p>不打开Segment情况下，</p><p>rd_opt_level:</p><ol><li>no_rd</li><li>rd_opt_basic</li><li>rd_opt_trellis, perform trellis-quant on the final decision only</li><li>rd_opt_trellis_all</li></ol><p>if rd_opt_level &lt; rd_opt_basic&gt;, then use <code>VP8EncLoop</code></p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://developers.google.com/speed/webp">Official-Webp-Doc</a><br><a href="https://medium.com/@tgpski/react-native-webp-reducing-bundle-binary-sizes-increase-speed-with-webp-image-format-aa9b1aa11405">React Native using Webp</a><br><a href="https://chromium.googlesource.com/webm/libwebp/+/HEAD/doc/tools.md">Webp Tools</a><br><a href="https://www.webmproject.org/docs/encoder-parameters/">VP8 Encode Parameter Guide</a><br><a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37073.pdf">VP8 Tech Overview</a><br><a href="https://developers.google.com/speed/webp/docs/compression">Webp Compression Techniques</a>    </p>]]>
    </content>
    <id>https://blog.zipavif.com/2023/10/24/webp-intra/</id>
    <link href="https://blog.zipavif.com/2023/10/24/webp-intra/"/>
    <published>2023-10-24T22:05:27.000Z</published>
    <summary>
      <![CDATA[<h2 id="What-is-Webp"><a href="#What-is-Webp" class="headerlink" title="What is Webp?"></a>What is]]>
    </summary>
    <title>Webp Introduction</title>
    <updated>2026-05-31T23:22:57.965Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Machine Learning" scheme="https://blog.zipavif.com/categories/Machine-Learning/"/>
    <category term="nni" scheme="https://blog.zipavif.com/tags/nni/"/>
    <category term="hpo" scheme="https://blog.zipavif.com/tags/hpo/"/>
    <content>
      <![CDATA[<p>nni是微软的一个AutoML工具，可以用来做一个自动化特征选择，自动剪枝和量化，神经网络架构搜索以及超参数调优。本文重点介绍下使用nni做超参数调优部分</p><h2 id="支持的算法"><a href="#支持的算法" class="headerlink" title="支持的算法"></a>支持的算法</h2><p>nni中包含了好多种超参数调优算法，大概有三类搜索策略，</p><h3 id="Exhaustive-seach"><a href="#Exhaustive-seach" class="headerlink" title="Exhaustive seach"></a>Exhaustive seach</h3><ol><li>Grid Search</li><li>Random</li></ol><h3 id="Heuristic-Search"><a href="#Heuristic-Search" class="headerlink" title="Heuristic Search"></a>Heuristic Search</h3><ol><li>Anneal</li><li>Evolution</li><li>Hyperband</li><li>PBT</li></ol><h3 id="Bayesian-optimization"><a href="#Bayesian-optimization" class="headerlink" title="Bayesian optimization"></a>Bayesian optimization</h3><ol><li>BOHB</li><li>DNGO</li><li>GP</li><li>Metis</li><li>SMAC</li><li>TPE</li></ol><h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><p>使用nni需要准备三个文件，包括</p><ol><li>nni_search.py: 计算每个参数的score</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">import nni</span><br><span class="line"></span><br><span class="line">def main():</span><br><span class="line">    para = nni.get_next_parameter()</span><br><span class="line">    x = para[&#x27;x&#x27;]</span><br><span class="line">    # square(x) = 2</span><br><span class="line">    score = abs(x*x - 2)</span><br><span class="line">    nni.report_final_result(score)</span><br><span class="line"></span><br><span class="line">if __name__ == &#x27;__main__&#x27;:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure><ol><li><p>search_space.json: 定义参数搜索的空间</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">        &quot;x&quot;: &#123;&quot;_type&quot;: &quot;uniform&quot;, &quot;_value&quot;: [1, 2]&#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>config.yml: nni配置文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">experimentName: search_sqrt_2</span><br><span class="line"></span><br><span class="line"># 并行度</span><br><span class="line">trialConcurrency: 1</span><br><span class="line"></span><br><span class="line"># 最大允许时长,</span><br><span class="line">maxExecDuration: 1h</span><br><span class="line"># 最多的运行次数，如果不设置则意味着永远不会停止</span><br><span class="line">maxTrialNum: 10</span><br><span class="line"></span><br><span class="line">#choice: local, remote</span><br><span class="line">trainingServicePlatform: local</span><br><span class="line"></span><br><span class="line"># search_space file</span><br><span class="line">searchSpacePath: search_space.json</span><br><span class="line"></span><br><span class="line">#choice: true, false</span><br><span class="line">useAnnotation: false</span><br><span class="line"></span><br><span class="line">tuner:</span><br><span class="line">  #choice: TPE, Random, Anneal, Evolution, BatchTuner, MetisTuner</span><br><span class="line">  #SMAC (SMAC should be installed through nnictl)</span><br><span class="line">  builtinTunerName: TPE</span><br><span class="line">  classArgs:</span><br><span class="line">    #choice: maximize, minimize</span><br><span class="line">    optimize_mode: minimize</span><br><span class="line"></span><br><span class="line">trial:</span><br><span class="line">  command: python3 nni_search.py</span><br><span class="line">  codeDir: .</span><br><span class="line">  gpuNum: 0</span><br></pre></td></tr></table></figure></li></ol><p>运行命令:<br><code>nnictl create --config config.yml</code> 启动试验，nni会打印出具体配置，并启动一个webserver，可以检查试验结果，以下为上面例子启动后的输出:<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">[2023-10-06 21:51:13] WARNING: Config field &quot;authorName&quot; is no longer supported and has been ignored</span><br><span class="line">[2023-10-06 21:51:13] WARNING: You are using legacy config file, please update it to latest format:</span><br><span class="line">================================================================================</span><br><span class="line">experimentName: search_sqrt_2</span><br><span class="line">trialConcurrency: 1</span><br><span class="line">maxExperimentDuration: 1h</span><br><span class="line">maxTrialNumber: 100</span><br><span class="line">searchSpaceFile: search_space.json</span><br><span class="line">useAnnotation: false</span><br><span class="line">trialCommand: python3 nni_search.py</span><br><span class="line">trialCodeDirectory: .</span><br><span class="line">trialGpuNumber: 0</span><br><span class="line">tuner:</span><br><span class="line">  name: TPE</span><br><span class="line">  classArgs:</span><br><span class="line">    optimize_mode: minimize</span><br><span class="line">trainingService:</span><br><span class="line">  platform: local</span><br><span class="line">================================================================================</span><br><span class="line">Reference: https://nni.readthedocs.io/en/stable/reference/experiment_config.html</span><br><span class="line">[2023-10-06 21:51:13] Creating experiment, Experiment ID: vl4y6ge3</span><br><span class="line">[2023-10-06 21:51:13] Starting web server...</span><br><span class="line">[2023-10-06 21:51:14] Setting up...</span><br><span class="line">[2023-10-06 21:51:14] Web portal URLs: http://127.0.0.1:8080 http://192.168.50.103:8080</span><br><span class="line">[2023-10-06 21:51:14] To stop experiment run &quot;nnictl stop vl4y6ge3&quot; or &quot;nnictl stop --all&quot;</span><br><span class="line">[2023-10-06 21:51:14] Reference: https://nni.readthedocs.io/en/stable/reference/nnictl.html</span><br></pre></td></tr></table></figure></p><p>运行完成以后，通过<br><code>nnictl stop -all</code>来停止试验</p><h2 id=""><a href="#" class="headerlink" title=" "></a> </h2>]]>
    </content>
    <id>https://blog.zipavif.com/2023/10/06/nni-hpo/</id>
    <link href="https://blog.zipavif.com/2023/10/06/nni-hpo/"/>
    <published>2023-10-06T13:22:07.000Z</published>
    <summary>
      <![CDATA[<p>nni是微软的一个AutoML工具，可以用来做一个自动化特征选择，自动剪枝和量化，神经网络架构搜索以及超参数调优。本文重点介绍下使用nni做超参数调优部分</p>
<h2 id="支持的算法"><a href="#支持的算法" class="headerlink"]]>
    </summary>
    <title>Use nni to optimize sysmtem automatically</title>
    <updated>2026-05-31T23:22:57.965Z</updated>
  </entry>
  <entry>
    <author>
      <name>Wayne</name>
    </author>
    <category term="Debug" scheme="https://blog.zipavif.com/categories/Debug/"/>
    <category term="Test" scheme="https://blog.zipavif.com/tags/Test/"/>
    <content>
      <![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]>
    </content>
    <id>https://blog.zipavif.com/1970/01/01/hello-world/</id>
    <link href="https://blog.zipavif.com/1970/01/01/hello-world/"/>
    <published>1970-01-01T00:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a>]]>
    </summary>
    <title>Hello World</title>
    <updated>2026-05-31T23:22:57.965Z</updated>
  </entry>
</feed>
