[{"content":"昨天捣鼓了一下一些网站矩阵，还是挺有意思的，比如搭建了基于somnus.top的子网站，比如docs.somnus.top、paper.somnus.top，lab.somnus.top，status.somnus.top\n现在最清晰的就是这样一套搭建的逻辑，除了status这个需要定时执行的网站以外，其他都是静态网页，通过GitHub actions部署然后走GitHub pages发布，再自定义域名转接到对应的pages上。分别介绍一下这些网站的原理。\nstatus # 先介绍最特殊的这个状态监测网站，是用来检测网站是否能正常工作，其实那些静态发布的网站几乎不可能出现问题，因为他们都是不会有什么变化的，除非做出一些commit更改，而每次commit都是可控的（通常不会改他的逻辑，只是添加内容），最容易出问题的还是那个部署在火山云服务器的vaultwarden密码管理器，但是幽默的地方来了，这个status和vaultwarden部署在同一个服务器，所以除非vaultwarden的docker容器自己出问题，不然的话这个status根本没办法起到作用，我估计这两个服务应该分开放，不然的话，是不是没有容灾性😅（我猜的，不知道这个词是否合适）。\n技术细节：status使用的是现成的开源方案uptime-kuma，不光简洁又好看，效果还挺好的。 如图，就是uptime-kuma的效果，对于我的这些网站服务，他是直接通过https来检测网站是否正常运行的。 如果返回的状态码属于设定范围，则认定为正常。对于那些静态网页，我设定的状态码范围是200-299，而对于vaultwarden，我设定的范围是200-399。\n","date":"2026-05-27","externalUrl":null,"permalink":"/diary/2026-05-27/","section":"日记","summary":"昨天捣鼓了一下一些网站矩阵，还是挺有意思的，比如搭建了基于somnus.top的子网站，比如docs.somnus.top、paper.somnus.top，lab.somnus.top，status.somnus.top\n","title":"2026-05-27","type":"diary"},{"content":"","date":"2026-05-27","externalUrl":null,"permalink":"/categories/journal/","section":"分类","summary":"","title":"Journal","type":"categories"},{"content":"学习、项目、实验和一些被密码保护起来的日常。\n","date":"2026-05-27","externalUrl":null,"permalink":"/","section":"Somnus","summary":"学习、项目、实验和一些被密码保护起来的日常。","title":"Somnus","type":"page"},{"content":"","date":"2026-05-27","externalUrl":null,"permalink":"/categories/","section":"分类","summary":"","title":"分类","type":"categories"},{"content":"一些更日常、更轻量的记录。\n","date":"2026-05-27","externalUrl":null,"permalink":"/diary/","section":"日记","summary":"生活复盘、个人随笔、私密记录和阶段性心情。","title":"日记","type":"diary"},{"content":" 智慧城市与交通学院本科毕业设计（论文）数字化档案检查清单 # 专业：智能制造工程\n学号：2022116717\n姓名：陈磊\n建议根文件夹名：智能制造工程_2022116717_陈磊\n必须归档材料（1-10） # 1. 本科毕业设计（论文）Word：智能制造工程_2022116717_陈磊_基于深度学习的双目立体匹配优化与轻量化方法研究.docx\n1. 本科毕业设计（论文）PDF：智能制造工程_2022116717_陈磊_基于深度学习的双目立体匹配优化与轻量化方法研究.pdf\n2. 外文翻译 Word：智能制造工程_2022116717_陈磊_外文翻译.docx\n2. 外文翻译 PDF：智能制造工程_2022116717_陈磊_外文翻译.pdf\n3. 毕设评分表（竖版）PDF：智能制造工程_2022116717_陈磊_毕设评分表.pdf\n4. 答辩记录表 PDF：智能制造工程_2022116717_陈磊_答辩记录表.pdf\n5. 评审意见表 PDF：智能制造工程_2022116717_陈磊_评审意见表.pdf\n6. 查重报告 PDF：智能制造工程_2022116717_陈磊_查重报告.pdf\n7. AIGC 检测报告 PDF：智能制造工程_2022116717_陈磊_AIGC 检测报告.pdf\n8. 开题报告 Word：智能制造工程_2022116717_陈磊_开题报告.doc\n8. 开题报告 PDF：智能制造工程_2022116717_陈磊_开题报告.pdf\n9. 中期检查报告 Word：智能制造工程_2022116717_陈磊_中期检查报告.doc\n9. 中期检查报告 PDF：智能制造工程_2022116717_陈磊_中期检查报告.pdf\n10. 中期检查评分表 PDF：智能制造工程_2022116717_陈磊_中期检查评分表.pdf\n限制性归档材料（如有则提交） # 11. 题目修改表 PDF：智能制造工程_2022116717_陈磊_题目修改表.pdf\n12. 缓答辩申请表 PDF：智能制造工程_2022116717_陈磊_缓答辩申请表.pdf\n13. 图纸类文件：智能制造工程_2022116717_陈磊_图纸名称\n14. 其它附件：智能制造工程_2022116717_陈磊_材料名称\n备注 # 清单要求 1-10 为必须归档材料，当前必需归档材料已齐全。\n第 11-14 项为限制性归档材料，仅在实际存在相关材料时提交。\n查重报告和 AIGC 检测报告当前仅发现 PDF 文件；若学校系统另行导出了非 PDF 原文件，也需要一并补充。\n智慧城市与交通学院本科毕业设计（论文）纸质档案袋检查清单 # 学院：智慧城市与交通学院 专业：智能制造工程 学号：2022116717 姓名：陈磊 论文题目：基于深度学习的双目立体匹配优化与轻量化方法研究 必须归档材料（1-11） # 1. 本科毕业设计（论文）：1 本，A4 双面打印，胶装，带学校毕业论文封面，格式按《西南交通大学本科毕业设计（论文）撰写规范》。 2. 外文翻译：1 本，A4 双面打印，带学校外文翻译封面，按扉页、中文、英文顺序排版。 3. 毕设评分表（竖版）：1 页，原件，需有评审成绩（含单项评分）及评审组组长签字，时间填写答辩时间。 4. 答辩记录表：1 页，原件，需完整填写，所有答辩评委需签字。 5. 评审意见表：1 页，由论文指导老师和论文评阅人填写评审意见并签字，时间需在答辩之前。 6. 查重报告：1 页，打印查重报告首页即可。 7. AIGC 检测报告：1 页，打印 AIGC 检测报告首页即可。 8. 毕业设计（论文）指导纪要：1 本，完整填写指导内容，指导教师需签字。 9. 毕业设计（论文）开题报告：1 本，完整填写指导内容，指导教师需签字。 10. 毕业设计（论文）中期检查报告：1 本，完整填写指导内容，需由指导教师和系室负责人或中期检查答辩组组长签字。 11. 毕业设计（论文）中期检查评分表：1 页，原件，需有评审成绩及评审组组长签字，时间填写中期检查答辩时间。 限制性归档材料（如有则提交） # 12. 毕业设计（论文）题目修改表：1 页，原件，需完整填写，由指导老师、系室负责人、学院教学负责人签字。 13. 毕业设计（论文）缓答辩申请表：1 页，如有缓答辩则需提供，原件需完整填写，由指导老师、系室负责人、学院教学负责人签字。 14. 图纸类文件：若干，如有则需提供，折叠为 A4 幅面。 15. 其它附件：若干，由指导教师指定，A4 幅面。 纸质版备注 # 纸质清单要求 1-11 为必须归档材料，当前必需归档材料已齐全。 第 12-15 项为限制性归档材料，如有则必须提供；已存在题目修改表，因此第 12 项需要放入袋内。 档案袋封面需完整填写：学院写“智慧城市与交通学院”，专业写“智能制造工程”，指导老师、题目、学号、姓名需与教务网和纸质材料一致。 本人材料属于毕业论文类型，涉及第 1、9、10、11、12 项时，页眉页脚等相关格式处应使用“毕业论文”，不要保留“毕业设计（论文）”。 other # 今日女盆友来成都，有没有懂的。\n","date":"2026-05-21","externalUrl":null,"permalink":"/diary/2026-05-21/","section":"日记","summary":"智慧城市与交通学院本科毕业设计（论文）数字化档案检查清单 # 专业：智能制造工程\n","title":"2026-05-21","type":"diary"},{"content":" 改进 文献格式一致 不足和展望不需要引用文献 页底距统一 有一个公式要居中和添加编号 第五章标题详细一点 柱状图表封起来 第一张每个方法都要有一个文献 ","date":"2026-05-19","externalUrl":null,"permalink":"/diary/2026-05-19/","section":"日记","summary":" 改进 文献格式一致 不足和展望不需要引用文献 页底距统一 有一个公式要居中和添加编号 第五章标题详细一点 柱状图表封起来 第一张每个方法都要有一个文献 ","title":"2026-05-19","type":"diary"},{"content":"","date":"2026-05-15","externalUrl":null,"permalink":"/tags/ai/","section":"Tags","summary":"","title":"Ai","type":"tags"},{"content":"","date":"2026-05-15","externalUrl":null,"permalink":"/categories/learning/","section":"分类","summary":"","title":"Learning","type":"categories"},{"content":"","date":"2026-05-15","externalUrl":null,"permalink":"/tags/learning/","section":"Tags","summary":"","title":"Learning","type":"tags"},{"content":"","date":"2026-05-15","externalUrl":null,"permalink":"/tags/llm/","section":"Tags","summary":"","title":"LLM","type":"tags"},{"content":" 位置编码 # 卷积具有局部性，天然地会注意元素之间的相对位置，但是基于自注意力的transformer模型则对位置不敏感，因此必须要把元素的位置信息在embedding阶段传给元素。 比如：\n1我 爱 你 2你 爱 我在自注意力的理论中，这两个句子的表意是一样的，但是很明显这两者是天差地别的。\n绝对位置编码 # 在早期的BERT、GPT2等模型中，会直接将绝对位置编码加入到embedding中，但是绝对位置编码又分为两种\n可学习的绝对位置编码：直接对不同位置随机初始化一个position embedding，将其加入到文本的embedding中，但是这样的方法引入了大量可学习的参数，需要大量数据才能训练。 固定绝对位置编码：attention is all you need中使用的三角位置编码 公式如下\n$$ \\begin{aligned} PE_{(pos,2i)}=\\sin(\\frac{pos}{10000^{\\frac{2i}{d_{model}}}}) \\\\ PE_{(pos,2i+1)}=\\cos(\\frac{pos}{10000^{\\frac{2i}{d_{model}}}}) \\end{aligned} $$ 其中$d_{model}$是位置编码的长度，$i \\in [0,1,\u0026hellip;,(d_{model}-1)/2]$。 采用这种设计，对于pos+k的位置的位置编码可以通过pos位置的位置编码线性表示得到。\n相对位置编码 # 是指将两个token的相对位置信息添加到对应的attention值中。 要对于相对距离远的进行惩罚。 Attention with linear biases enables input length extrapolation（ALiBi） # 上图中就是ALiBi，传统的绝对位置编码会在训练时添加一个固定的向量，模型可能会过拟合这些特定长度的向量，于是ALiBi在分数计算的时候就添加了一个线性偏置，减少了模型对特定长度序列的依赖，提升了其对于未知长度序列的泛化性。\nALiBi的位置偏差会随token距离线性增加。 ALiBi鼓励模型关注更近的位置，但又不会完全排除远处的依赖。 XLNET # T5 # DeBERTa # 旋转位置编码RePE # RoPE实现了绝对位置编码和相对位置编码的统一，（通过绝对编码的形式实现了相对编码的效果）。RoPE最大意义就是在保留token位置信息的同时没有对token的语义产生污染。 RoPE将输入的序列位置信息通过旋转操作，嵌入到self-attention的计算中。 这个视频讲的很清楚，分别讲了为什么要用位置编码和RoPE如何推导。\n旋转矩阵 # $$ \\left\\{ \\begin{matrix} \\cos \\alpha \u0026 -\\sin\\alpha\\\\ \\sin\\alpha \u0026 \\cos \\alpha \\end{matrix}\\right\\} $$ 上面这个公式就是一个旋转矩阵，他乘上$\\left{ \\begin{matrix} 0 \\ 1\\end{matrix} \\right}$，就表明让这个向量在坐标轴沿逆时针旋转$\\alpha$的角度。 如图，图中就是逆时针旋转30度。我们可以观察到表明语义的长度没有变化的同时，添加了表明位置信息的旋转角度$\\alpha$。 为了表明，于是便可以通过对原矩阵乘上一个旋转矩阵来添加其位置信息。如下： $$ \\begin{align} q'\u0026=R(m\\theta)q \\\\ k'\u0026=R(n\\theta)k \\end{align} $$ 对于p和q就分别乘上两个旋转矩阵，来表明其位置信息。 $$ \\begin{align} Score=(q')^T \\cdot k'\u0026=(R(m\\theta)\\cdot q)^T \\cdot R(n\\theta)\\cdot k \\\\ \u0026=q^T \\cdot R(m\\theta)^T\\cdot R(n\\theta) \\cdot k\\\\ \u0026=q^T\\cdot R((n-m)\\theta)\\cdot k \\end{align} $$ 拓展到普遍情况 # 上述是基于两维矩阵举的例子，实际情况中的token都是上千维，对于这种情况，RoPE采用了分治法。对于4096维度的矩阵，就给他拆成2048对。对于每一对都乘上旋转矩阵、添加位置信息。 问题 # 旋转的话，10度和370度表示的意思就可能重叠，这样的话根本没办法表明独特的位置信息。为了解决这个问题，就可以利用刚刚上面的基本角度$\\theta$，对于不同维度的矩阵，取用不一样大小的$\\theta$，维度越低，$\\theta$越大；反之，则越小。 也就是说，维度越低的矩阵，对于位置变化会更敏感，维度越高则越钝感。 RoPE的基本角度计算公式也是参考三角函数编码的。 $$ \\theta_i=10000^{-\\frac{2(i-1)}{d_{model}}} $$ 因此就不需要担心重叠的问题，因为一个token的位置信息是由所有的旋转矩阵决定的，虽然低维度可能出现重叠，但是高维度还是能表明其独特性的。\n准确说是很难重复，实际上也是可能重复的，但是重复周期会很长。\n相对正余弦编码 # 正余弦编码虽然也包含相对位置信息，如下 $$ \\begin{align} Q \u0026=W_q(X_m+P_m) \\\\ K\u0026=W_k(X_n+P_n) \\\\ Score\u0026=(X_m+P_m) (X_n+P_n)^T \\end{align} $$ 注意力分数计算已经简化了。展开后如下 $$ \\begin{align} Score \u0026=(X_m+P_m)(X_n^T+P_n^T) \\\\ \u0026=X_mX_n+P_mX_n^T+X_mP_n^T+P_mP_n^T \\end{align} $$ 其中$X_mX_n$是有效语义信息，而$P_mP_n^T$是有效位置信息，其余都是无效信息（噪声）。RoPE则如下： $$ \\begin{align} Score\u0026=QK^T\\\\ \u0026=(R_mX_m)(R_nX_n)^T\\\\ \u0026=X_mR_{n-m}X_n^T \\end{align} $$ 很明显全是有效信息。 信息的有效性直接关系到模型的质量和训练成本（噪声大的模型需要更多的训练数据）。 这也就是RoPE能被广泛使用的原因。\n","date":"2026-05-15","externalUrl":null,"permalink":"/notes/llm04-position-encoding/","section":"知识笔记","summary":"位置编码 # 卷积具有局部性，天然地会注意元素之间的相对位置，但是基于自注意力的transformer模型则对位置不敏感，因此必须要把元素的位置信息在embedding阶段传给元素。 比如：\n","title":"Llm04 Position Encoding","type":"notes"},{"content":"","date":"2026-05-15","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"这里放更偏自用检索的材料：学习记录、技术初体验、算法速记和配置备忘。\n","date":"2026-05-15","externalUrl":null,"permalink":"/notes/","section":"知识笔记","summary":"碎片化学习记录、速查表、课程复习和文献/算法笔记。","title":"知识笔记","type":"notes"},{"content":"最近被毕设论文的格式问题折磨的很难受，因为我用的是typst模版，只能导出pdf，不支持原生导出docx，但是毕设论文提交强制要求docx或者doc。\n1解决方案 # 1.1pdf2docx # 我女朋友有wps会员（顺便一提这个wps会员还走了我们学校的报销途径），然后wps会员支持pdf转word，于是我便使用了他的这个功能。其实效果还是可以的，大部分该转换的图表都可以正常转换，但是也存在很多问题，比如：\n过多的分页符，似乎是因为wps的某种机制，他会把pdf某一页下面留空（哪怕是一点点的空）都判定为分页符，实际上可能是因为图片导致的留空 字体无法主动识别，wps默认转word，会把字体提取成默认字体，macbook上就是苹方，Windows上就是微软雅黑（我女朋友在她电脑上测试的）。 图片排版错乱，这个情况只是会部分出现。 1.2排版优化 # 针对上面的问题，如果要手动改，其实也可以，但我是真的懒😭，原本听同学建议，准备去淘宝上找一个代排版的，后来在加上那个人微信之后，他要我发论文和格式规范要求，我又有点担心会因为学校信息泄露，被勒索威胁什么。 于是我准备codex来辅助我对这个论文进行排版。 我先是在codex的要求下，安装了libreoffice，因为codex在渲染word文档的时候需要使用soffice。然后我就在一步步指令让他对我的word文档进行格式修改。 效果还是意料之外的挺好的。 2 SWJTU 130周年 # 今天是西南交的120周年，还是祝西南交生日快乐，等会去看看有没有什么好玩的活动。\n","date":"2026-05-15","externalUrl":null,"permalink":"/diary/2026-05-15/","section":"日记","summary":"最近被毕设论文的格式问题折磨的很难受，因为我用的是typst模版，只能导出pdf，不支持原生导出docx，但是毕设论文提交强制要求docx或者doc。\n","title":"2026-05-15","type":"diary"},{"content":"女朋友要来成都玩，最近使用qwen和chatgpt image2做了旅游规划，别说，效果还挺好的。\nflowchart LR A[双流机场] B[酒店1] C[景点1] D[西南交大] E[景点2] F[成都西站] G[酒店2] H[九寨沟] I[酒店3] J[天府机场] A--\u003eB--\u003eC--\u003eD--\u003eB--\u003eE--\u003eF--\u003eG--\u003eH--\u003eI--\u003eJ 以下是我的答辩记录： 学生陈磊围绕《基于深度学习的双目立体匹配优化与轻量化方法研究》进行汇报，介绍了双目立体匹配的研究背景、RAFT-Stereo 基线模型、精度优化探索及 FP16 半精度轻量化实验结果。\n评委主要提出以下意见：一是论文格式仍存在少量不规范之处；二是答辩 PPT 中轻量化部分文字较多，缺少原理示意图；三是论文中轻量化改进主要为 FP32 转 FP16，方案相对简单；四是精度优化工作应在论文中独立展开。学生回答认为，正因轻量化方案较简单，才补充了视差细化、边缘损失和局部解冻等精度优化工作，并表示后续将按评委意见完善格式、补充图示，调整论文结构。\n","date":"2026-05-14","externalUrl":null,"permalink":"/diary/2026-05-14/","section":"日记","summary":"女朋友要来成都玩，最近使用qwen和chatgpt image2做了旅游规划，别说，效果还挺好的。\n","title":"2026-05-14","type":"diary"},{"content":"今日毕设答辩\n陈磊毕设答辩讲稿 2000字逐页口语版 # 第1页 # 各位老师好，我是陈磊。我的毕设题目是《基于深度学习的双目立体匹配优化与轻量化方法研究》。这项工作主要围绕两个问题：一个是提升双目匹配在边缘、遮挡等困难区域的精度，另一个是降低模型部署时的计算和显存开销。\n第2页 # 我的汇报分为五部分：研究背景、相关理论与基线模型、精度优化方法、模型轻量化实现，以及最后的实验结果和总结。\n第3页 # 首先介绍研究背景与意义，主要说明为什么要研究双目立体匹配，以及它目前还存在哪些实际问题。\n第4页 # 深度信息是机器理解三维环境的基础。比如机器人避障、自动驾驶感知、三维重建，都需要知道物体离相机有多远。双目立体匹配通过左右图像的视差来恢复深度，相比激光雷达和结构光，成本更低、结构更简单。但它也容易受到遮挡、深度突变、弱纹理和光照变化影响，所以提高精度和效率都很重要。\n第5页 # 现有深度学习方法已经提升了整体精度，但还有两个瓶颈。第一，边缘、细小结构和遮挡区域仍然容易出错，视差图会有模糊现象。第二，高性能模型通常推理慢、显存占用高，不方便部署。因此本文以 RAFT-Stereo 为基础，分别做局部精度优化探索和轻量化部署分析。\n第6页 # 接下来介绍相关理论与基线模型，也就是本文采用的 RAFT-Stereo。\n第7页 # RAFT-Stereo 的核心流程有三步。第一步是多尺度特征编码，提取左右图像的上下文和纹理信息。第二步是构建全对场相关体，计算左右图像特征之间的相似度。第三步是通过 GRU 循环更新视差，多轮迭代修正结果。它的优势是精度高，但计算量也比较大。\n第8页 # 在 Middlebury 2014 数据集上，基线模型的 EPE 是 2.3758，异常点率 D1 是 12.0526。EPE 表示预测视差和真实视差的平均误差，D1 表示异常点比例，都是越小越好。从图中 backpack 场景可以看到，整体视差结构能恢复出来，但局部边缘和细节仍有优化空间。\n第9页 # 下面进入精度优化方法探索。这部分主要想验证：在 RAFT-Stereo 这种强基线模型上，简单的结构和损失改进是否还能带来明显提升。\n第10页 # 第一种方法是输出端视差细化模块。我的想法是，基线模型已经给出比较完整的视差图，但边缘和细节不够精细，所以在输出端加入残差细化头，让它结合图像纹理和轮廓信息，对原始视差进行局部修正。\n第11页 # 第二种方法是边缘感知联合损失。普通损失对所有像素比较平均，但实际更容易出错的是边缘和深度突变位置。因此我根据图像梯度提取边缘响应，构建权重图，让边缘区域的误差在训练时受到更大惩罚，从而引导模型关注边界模糊问题。\n第12页 # 第三种方法是局部解冻微调。由于数据规模有限，如果全参数微调，容易破坏预训练特征。所以我冻结特征提取骨干，只对部分模块训练。方案 A 是开放相关体和 GRU 更新模块，方案 B 是只训练新增细化头，用来对比不同局部训练策略的效果。\n第13页 # 接下来是模型轻量化实现。这部分关注模型在实际部署时的速度、显存和存储体积。\n第14页 # 高精度立体匹配模型的部署压力主要有三点：相关体和迭代机制会占用较多显存；前向计算复杂，推理时间较长；模型权重文件较大，不利于边缘设备部署。因此轻量化的目标不是单纯压缩模型，而是在精度、速度和资源占用之间取得平衡。\n第15页 # 我比较了几种轻量化路线。结构重设计和知识蒸馏需要重新训练，开发成本较高；剪枝可能损害边缘细节。本文最终选择 FP16 半精度推理，因为它不改变原网络结构，实现简单，可以利用 GPU 张量核心加速，并且通常精度损失较小。\n第16页 # FP16 的基本原理是把推理中的权重、偏置、输入张量和中间特征，从 FP32 转换为 FP16。由于这里只用于推理阶段，不涉及反向传播和梯度更新，所以数值稳定性风险相对较低。同时现代 GPU 对半精度计算有硬件支持，能够提升吞吐并降低显存。\n第17页 # 半精度推理流程是：先加载原 FP32 模型，再转换模型参数和张量，之后执行 FP16 前向推理，最后输出视差图。评价时我从四方面看效果：EPE 和 D1 看精度，平均耗时和 FPS 看速度，最大 CUDA 显存看资源占用，权重体积看部署成本。\n第18页 # 下面进入实验结果与总结，先看精度优化结果，再看轻量化结果。\n第19页 # 精度优化的结果显示，基线 EPE 为 2.3758，D1 为 12.0526。只加细化头后，EPE 为 2.376，D1 为 12.0609，基本没有提升。加入边缘损失后，EPE 为 2.3757，变化也很小。局部解冻后 EPE 变为 2.4377，反而下降。说明简单后端修正很难突破强基线。\n第20页 # 这一页是 Jadeplant 场景的可视化对比。可以重点看叶片边缘、前景背景交界处和细小结构。不同方案整体差异并不明显，和前面的定量结果一致，说明输出端细化对局部可能有轻微影响，但没有稳定带来明显提升。\n第21页 # 轻量化结果更明显。FP16 后，EPE 从 2.376 变为 2.353，精度基本稳定；推理时间从 209.8 毫秒降到 173.6 毫秒，下降约 17.2%；显存从 845MB 降到 662MB，下降约 21.6%；模型体积从 43MB 降到 22MB，接近压缩一半。\n第22页 # 本文结论主要有三点。第一，构建了从细化头、边缘损失到局部解冻的评估链路。第二，实验说明强基线的精度瓶颈不能只靠输出端修补，更需要改进特征融合和遮挡建模。第三，FP16 在保持精度稳定的同时，显著降低了推理时间、显存和模型体积。\n第23页 # 不足和展望方面，后续可以从三点继续做：算法上加入多尺度特征融合和注意力机制；数据集上扩展到 Scene Flow、KITTI 等更多场景；部署上继续探索 INT8 量化和剪枝，并在 Jetson 这类边缘设备上测试实时性和功耗。\n第24页 # 以上就是我的全部汇报。本文围绕 RAFT-Stereo，从精度优化和轻量化部署两个角度进行了实验分析。恳请各位老师批评指正，谢谢各位老师。\n改进建议 # 不要因为图片留出大范围的空白。 把第二章中的匹配优化部分独立出来。 修改几个老师提到的格式问题。 缺少卷号的参考文献补充一下卷号 第四章添加一个引言 ","date":"2026-05-13","externalUrl":null,"permalink":"/diary/2026-05-13/","section":"日记","summary":"今日毕设答辩\n陈磊毕设答辩讲稿 2000字逐页口语版 # 第1页 # 各位老师好，我是陈磊。我的毕设题目是《基于深度学习的双目立体匹配优化与轻量化方法研究》。这项工作主要围绕两个问题：一个是提升双目匹配在边缘、遮挡等困难区域的精度，另一个是降低模型部署时的计算和显存开销。\n","title":"2026-05-13","type":"diary"},{"content":"最近捯饬这个破博客网站就捯饬了好久，现在的效果还算挺满意的，之前就感觉走的优点太偏了，过分追求美术风格，导致已经偏离了我的初心。 原本是想做一些技术分享，现在已经变成了家豪风格，现在准备返璞归真。 找了一个新的主题，感觉很简洁。\n小项目 # 今天关注了一个小项目，就是这个greenwall刷绿墙的小项目，原本我是准备自己也刷一下我的仓库绿墙的，因为之前真的太空白了，好丑，好丑。 然后就关注到这个项目了。\n项目原理 # 这个项目其实我第一眼看到我就大概知道他的原理了，首先我们要知道git和github是两个东西。 git是一个用来进行代码管理的工具，而github最基本的功能就是一个放置代码的平台。github的绿墙是根据git的history来生成的，而你的项目什么时候commit，commit了什么东西，都是你自己可控的。同样你也可以指定commit的时间，不一定要是当下。至于我看到issue中有人问会不会被github官方封禁。 这个是肯定不会的，要知道github和git并不是捆绑的，我可以将两者连起来，但是同样也可以不连起来，只使用本地的git。所以我添加什么项目，项目之前有怎样的commit，都和github没关系。\n项目问题 # 这个项目是一个中国人做的，挺好的，现在已经有1.3k★，现在已经支持很多功能了，比如画笔功能，图片转绿墙形状，粘贴字母状绿墙： 然后这个仓库里面之前有人提交过一个pr，但是后来作者就没管了。 我准备自己vibe-coding一个fr，也实现同样的功能，希望能被merge，不过一定要写清楚fr的提交内容。\n端到端加密 # 最近捣鼓了一个博客网站的端到端加密，觉得还挺好玩的。\nflowchart A[本地客户端明文markdown] B[本地密文]","date":"2026-05-11","externalUrl":null,"permalink":"/diary/2026-05-11/","section":"日记","summary":"最近捯饬这个破博客网站就捯饬了好久，现在的效果还算挺满意的，之前就感觉走的优点太偏了，过分追求美术风格，导致已经偏离了我的初心。 原本是想做一些技术分享，现在已经变成了家豪风格，现在准备返璞归真。 找了一个新的主题，感觉很简洁。\n","title":"2026-05-11","type":"diary"},{"content":" 这篇文章需要解锁后查看正文。\nEnd-to-end encrypted\n私密正文 输入密码后，内容只会在当前浏览器中解密。 解密 LOCKED 7f 3a e1 90 2c b8 11 a4 d9 44 6b 0f c2 70 ae 19 03 af 8d 51 ee 6c 92 7b ","date":"2026-05-10","externalUrl":null,"permalink":"/diary/2026-05-10-%E7%A7%81%E5%AF%86%E6%97%A5%E8%AE%B0/","section":"日记","summary":" 这篇文章需要解锁后查看正文。\nEnd-to-end encrypted\n私密正文 输入密码后，内容只会在当前浏览器中解密。 解密 ","title":"2026-05-10 私密日记","type":"diary"},{"content":"","date":"2026-05-10","externalUrl":null,"permalink":"/tags/private/","section":"Tags","summary":"","title":"Private","type":"tags"},{"content":" 为什么要有tokenizer # tokenizer的作用是把文本序列转换成数字序列，即token编号，作为transformer的输入。\ngraph LR A[word] --tokenizer--\u003eB[token id] B --embedding--\u003eC[vector] C--\u003eD[...] word-based tokenizer # 将文本分成一个个词，优点是表达意思准确，但是问题是很容易把同一个意思的词分成很多类，比如cat和cats就会被分成两类，按照这样的编码方式，就会导致词表巨大，因此就需要巨大的embedding_matrix，导致空间复杂度和时间复杂度大幅上升。\n如果限制词表的大小，比如把词表上限设为10000，就会出现很多词都无法覆盖的情况，模型性能会很差。\ncharacter-based tokenizer # 按照每个字母来分词，比如\u0026quot;cat\u0026quot;就被分为'c','a','t'，优点是很容易表示英文，对于英文总共可能只需要256个序号来表示，对于任意文本都不会出现unknown的现象。 缺点也是显著的，\n每个字母没办法代表很多的含义，信息量太低了，导致模型性能也会很差；\n对于中文还是需要很大的词表；\n相对于word-based，token序列会过于长。\nsubword-based tokenizer # flowchart A[\"`word-based - 词表过大（5万~10万） - 运算量大`\"] B[\"character-based - token序列过长 - 信息量过低 - 语义捕获能力弱\"] C[subword-based] A ----\u003e C B ----\u003e C可以看到上述两种方法都有自己的缺点，而subword就是一种折中的方法。 subword划分更符合英文词群，能充分表达词意。\nflowchart A[dogs] B[dog] C[s] A----\u003eB A----\u003eC D[tokenizer] E[token] F[izer] D----\u003eE D----\u003eF BPE # 即byte-pair encoding，主要分成两部分，词频统计和词表合并。 首先先把所有的词按character切分，得到单词表，再所有词中的两两组合的单词组合统计频率，根据频率从高到低排，取出频率最高的那个两个单词的组合，把它加到词表中。然后再按照新的词表的词两两组合（此时会有三个单词组成词组），再统计频率，再将最高频率的词组加到词表中，以此循环，知道达到超参数设定的最大循环次数。\n具体流程可以看这个视频。 BPE的超参数是设定最大循环次数。\nBBPE即byte level BPE，即把每个字节视作基本的token，两个字节就可以合并表示Unicode，比如中文，阿拉伯文，表情符号。 WordPiece Tokenization # 大体是和BPE类似的，但是除了第一个字母，会添加##作为前缀\nflowchart LR A[word]--\u003eB[\"w,##o,##r,##d\"]使用联合概率来计算每个pair的得分。 $$pair得分=\\frac{pair出现的次数}{token1出现的次数 \\times token2出现的次数}$$ 证明这个wordpiece方法他会优先考虑单一token在词表中并不频繁的，将其合并起来。 比如unable的un、##able和hugging的hu、##gging，后者会更容易合并起来。\nUnigram tokenization # 首先是获得一个很大的词表，然后在尝试删除这个词表中的某个词，然后计算他的unigram loss。删除p%使得loss增加最少的token。\n前提：假设每个词的出现都是独立的。 unigram loss计算公式 $$ Unigramloss=\\sum frec(-log(P(word))) $$ 其中的frec是这个词出现的频率，P(word)是这个词出现的概率。 unigram是通过不断的迭代知道词表缩小到预设值。 为单词的每种划分算法非常耗时，采用更高效的维特比算法。 sentencePiece tokenization # BPE、WordPiece、Unigram的缺点 中文，韩文，日文等语言并不是通过空格来分词的。 对于特定语言可以使用pre-tokenization，但是不通用。 SentencePiece tokenization 将输入视为输入字节流，包括空格。 然后再使用byte-level BPE或unigram算法来构建适当的词汇表。 unigram算法经常在sentence piece中使用，是AIBERT、T5、mBART、BigBird和XLNet使用的算法。 Q\u0026amp;A # token是一个词，token_id是这个词对应的数字，vocabulary是词表，就是所有词的汇总。 因为如果直接按词处理的话，会出现太多的意思相近的词，比如dog和dogs就会被认为是两个词，词表会过大 按字符划分的话，词表的大小会小很多，但是每个字符的表意并不够丰富，导致模型效果会不好。 BPE的基本思想是词频统计和词表划分。 不知道 你这节已经有骨架了，差的是把几个概念说得更精确。逐题修一下。\ntoken / token id / vocabulary token 不一定是“一个词”。它可以是一个字、一个词、一个词片段、一个标点、一个空格片段，甚至代码里的符号片段。\n更准确地说：\ntoken：tokenizer 切出来的最小处理单元 token id：这个 token 在词表里的整数编号 vocabulary：token 到 id 的映射表 为什么不直接按词处理 你说的 dog/dogs 是对的，但还要补两个更关键的问题：\n词表会巨大，尤其中文、英文变形、专有名词、拼写错误、代码、URL 混在一起时。 会有 OOV，也就是词表外词。遇到没见过的新词、人名、产品名，就没法稳定表示。 为什么不完全按字符处理 对。再补一个核心代价：序列会变得很长。\n比如 transformerization 按字符可能十几个 token，按 subword 可能 3-4 个 token。序列越长，attention 成本越高，上下文窗口也越容易被占满。\nsubword tokenizer 的核心折中 这题可以这样答：\n高频词或常见片段尽量作为完整 token，低频词、生造词、专有名词拆成更小的子词片段。\n好处是：词表不会无限大，同时也不容易 OOV，序列长度也比字符级短。\nBPE 的基本思想 你的答案方向对，但还不够具体。BPE 可以这样理解：\n从字符级开始，反复统计最常一起出现的相邻片段，把它们合并成新的 token，直到达到目标词表大小。\n举例：\n1l o w 2l o w e r 3n e w e s t如果 l 和 o 经常相邻，就合并成 lo；如果 lo 和 w 经常相邻，就合并成 low。\ntokenizer 怎么影响上下文长度和计费 大模型按 token 处理上下文，很多 API 也是按 token 计费。\n所以 tokenizer 会影响：\n同一段文字会被切成多少 token 能塞进上下文窗口的内容有多少 输入/输出成本是多少 长文本、中文、代码、多语言混合时的实际效率 例子：如果一个 tokenizer 对中文切得很碎，同样一篇中文文章 token 数更多，就更贵，也更容易超过上下文长度。\n","date":"2026-05-09","externalUrl":null,"permalink":"/notes/llm03-tokenizer/","section":"知识笔记","summary":"为什么要有tokenizer # tokenizer的作用是把文本序列转换成数字序列，即token编号，作为transformer的输入。\n","title":"LLM03 Tokenizer","type":"notes"},{"content":"","date":"2026-05-09","externalUrl":null,"permalink":"/tags/encryption/","section":"Tags","summary":"","title":"Encryption","type":"tags"},{"content":"","date":"2026-05-09","externalUrl":null,"permalink":"/tags/privacy/","section":"Tags","summary":"","title":"Privacy","type":"tags"},{"content":" 这是一篇用于验证加密工作流的试点文章。文章可以正常打开，但正文需要解锁后查看。\n演示密码：somnus-demo\nEnd-to-end encrypted\n试点密文正文 输入这篇试点文档的密码。 解密 LOCKED 7f 3a e1 90 2c b8 11 a4 d9 44 6b 0f c2 70 ae 19 03 af 8d 51 ee 6c 92 7b ","date":"2026-05-09","externalUrl":null,"permalink":"/diary/%E5%8A%A0%E5%AF%86%E5%86%85%E5%AE%B9%E8%AF%95%E7%82%B9/","section":"日记","summary":" 这是一篇用于验证加密工作流的试点文章。文章可以正常打开，但正文需要解锁后查看。\n","title":"加密内容试点","type":"diary"},{"content":" transformer # transformer是在这篇attention is all you need中提出来的。\n上图就是该论文最核心的模型架构图，本文也是围绕着这个架构图来展开的。\nembedding # 由input embedding和位置编码相加得到，后面的文章详细介绍。\ninput embedding可以通过word2Vec，bert，OpenAI Embedding API等方式获取，目的是将文本映射到连续的向量空间（把文本变成模型能处理的向量）。 位置编码是为了捕捉输入中token的顺序信息，常用的有rope，绝对位置编码等 encoder（编码器） # 图片中的红色框内，就是encoder。\n可以看到encoder是有N个`multi-head attention`+`add\u0026norm`+`feed forward`+`add\u0026norm` 组成的。`multi-head attention`是多头注意力机制，在这个文章中有详细介绍。[self-attention](https://affine.somnus.top/workspace/09e2838e-0333-4d5c-80d5-bcae278e8e50/qQsakBqRrL2JR41Rk7p2h)，`add\u0026norm`是两个步骤，add是指把源数据和经过运算输出的数据叠加起来，norm则是对其进行归一化操作。公式如下： $$ LayerNormalization(X+Multi-Head Attention(X)) $$此处公式中用的是LayerNormalization，而对于norm的位置，也分成了pre-norm和post-norm，分别是指norm的操作在残差连接之前和之后。上图中就是post-norm。\nfeed forward即两个简单的全连接层。公式如下：\n$$ max(0,XW_1+b_1)X+b_2 $$Attention 负责** token 之间的信息交互**，让每个 token 根据上下文更新自己的表示；**FFN 负责对每个 token 各自做非线性变换**，提升表达能力。FFN 虽然看起来只是两层全连接，但它通常占 Transformer 参数量很大，不是“简单附属模块”。\ndecoder（解码器） # 可以看出来decoder相对于encoder是要复杂一点的，除了一个N次处理循环block以外，最后还有线形变换和softmax处理。\n在循环处理的block中也有不同，我们可以看到第一个多头注意力增加了一个masked，表明这个注意力机制有一个掩码矩阵。为什么要有掩码矩阵可以看self- attention这篇文章self-attention。上图中的第二个多头注意力机制是cross-attention，是指decoder层用来看encoder输出的注意力层。对于decoder-only是没有这个cross-attention的。\n最后还有一个softmax，根据前面的知识，在self-attention的模块中是存在softmax，而这两个softmax很明显负责的功能是不一样的。其中self-atttention中的softmax是用来告诉当前的位置应该关注哪些位置，而这里的softmax是表明下一个token应该表示词表里的哪个词。\nonly模块 # encoder-only # 常见的模型是：BERT，RoBERTa。\n它通常是双向注意力机制，即不需要要掩码，可以看见未来token。\n侧重于理解，所以它很适合理解完整输入，比如：\n文本分类 情感分析 句子匹配 decoder-only # 常见模型是：GPT，Mistral，LLaMa。\n它使用的是单向注意力机制，需要给未来token添加掩码，不可以可以看见未来token。\n侧重于生成，所以它天然适合生成：\n聊天 写作 代码生成 值得注意的一点是，现代的decoder-only大模型也可以作为理解任务，因为在模型训练的时候会投喂很多理解型的数据，因此很多的理解任务都被转成了生成任务。\nDecoder-only 模型通过预测下一个 token 学到了上下文表示；在回答时完整输入都位于它左侧，所以它能读完整问题，再把理解任务转化为生成答案。它不是像 BERT 那样双向编码全文，但足够大、数据足够多、训练方式足够好时，生成过程本身就承载了理解。\n解码策略 # 在自然语言生成的任务中，我们通常使用一个预先训练好的大模型来根据我们的输入生成输出文本，而大模型给的输出是下一个token的概率分布，而如何在这些概率分布中选择，便是解码策略。\n目前主流的解码策略有以下几种：\n贪心解码：即直接选择最大概率的token 随机采样：按照概率分布随机选择一个单词 beam search：维护一个大小为 k 的候选序列集合，每一步从每个候选序列的概率分布中选择概率最高的 k 个单词，然后保留总概率最高的 k 个候选序列。 以上的方法各有各的问题，而top-k和top-p采样就是介于贪心和随机采样之间的策略，也是目前大模型最常用的解码策略。\ntop-k采样 # 为什么不能直接用贪心解码，想象我们智能手机的输入法推荐下一个字，他就是贪心解码策略，直接给你按照从高到低概率排列，但是如果我们一直按第一个，会发现句子逐渐越来越重复。而top-k就是从概率最高的k个单词中，采用随机采样来选一个单词。\n上图中，紫色部分便是被选中的，可能被选择的词。\nTop-k 的优势是简单、稳定、能过滤低概率噪声，相对更多样；劣势是固定 k 太机械，容易在模型很确定时放得太宽、在模型不确定时收得太窄。\ntop-p采样 # top-k有个很明显的问题，就是这个k如何确定，如何选择才更合理，于是出现了动态设置 token 候选列表大小策略——即核采样（Nucleus Sampling）。\n由上图中可以看出来，top-p的策略是设定一个p，只保留从高到低累计概率小于p的token，这样就可以避免上面top-k的一些问题。\nTop-p 的优点是自适应、灵活、能过滤长尾，特别适合开放式生成；缺点是 p 需要调，分布平坦时候选可能过多，而且随机采样仍可能带来不稳定。\n在现代的大模型中，top-k和top-p往往都是同时采用的。即先进行top-k采样缩小候选范围，再在这个候选范围中采用top-p采样来保留高概率的候选集合。\n同时启用 top-k 和 top-p，是为了让 top-k 提供候选数量上限，让 top-p 根据概率分布动态收缩候选集合；两者结合能减少低质量长尾，又避免固定 k 过于机械。\ntemperature采样 # temperature采样的本质就是先对logits做一些缩放，再进行softmax。\n$$ p_i = \\frac {exp(z_i / T)}{\\sum_j exp(z_j / T) } $$$z_i$ = 第 i 个 token 的 logit，T = temperature，$p_i$ = 第 i 个 token 的采样概率\n结论就是，温度越高随机性越大，分布越均匀，越发散；温度越低，随机性越低，分布更尖锐，越保守。\n联合采样（top-k \u0026amp; top-p \u0026amp; Temperature） # 通常我们是将 top-k、top-p、Temperature 联合起来使用。使用的先后顺序是 top-k-\u0026gt;top-p-\u0026gt;Temperature。\n我们还是以前面的例子为例。\n首先我们设置 top-k = 3，表示保留概率最高的3个 token。这样就会保留女孩、鞋子、大象这3个 token。\n女孩：0.664 鞋子：0.199 大象：0.105 接下来，我们可以使用 top-p 的方法，保留概率的累计和达到 0.8 的单词，也就是选取女孩和鞋子这两个 token。接着我们使用 Temperature = 0.7 进行归一化，变成：\n女孩：0.660 鞋子：0.340 接着，我们可以从上述分布中进行随机采样，选取一个单词作为最终的生成结果。\nQ\u0026amp;A # Q1：Transformer block 里 attention 和 FFN 分别负责什么？\nA1：attention是主要的模块，是用来训练模型能关注更重要的信息，而FNN是两个简单的全连接层。\nQ2：Encoder 和 Decoder 最大区别是什么？\nA2：我认为最大的区别是encoder的输出可以输入到decoder中，decoder因此具有cross-attention功能，除此以外，还有一些区别，比如encoder的注意力是不需要掩码的。\nQ3：为什么 GPT 用 Decoder-only 架构？\nA3：GPT是generative pretrain transformer特指生成式的大模型，而decoder天生就更适合生成式的任务，因为他的单向注意力机制等等特性。\nQ4：logits、softmax、probability 三者是什么关系？\nA4：logits 是“还没正规化的偏好分数”；softmax 是“归一化成概率分布”；probability 是“最终每个 token 的概率”。\nQ5：temperature 变大/变小分别会怎样？\nA5：温度越高随机性越大，分布越均匀，越发散；温度越低，随机性越低，分布更尖锐，越保守。\nQ6：top-k 和 top-p 的区别是什么？\nA6：top-k是指定k个候选项，按照概率从高到低选择，而top-p是指定累计概率p，按照概率额从高到低选择累计概率小于p的候选。\n整体过了，尤其 Q4/Q5 很稳。帮你把几个点修准一点：\nQ1 需要补上关键分工：Attention 负责 token 之间的信息交互，让每个 token 根据上下文更新自己的表示；FFN 负责对每个 token 各自做非线性变换，提升表达能力。FFN 虽然看起来只是两层全连接，但它通常占 Transformer 参数量很大，不是“简单附属模块”。\nQ2 你的理解基本对，但“最大区别”可以更直接：Encoder 是双向理解，Decoder 是因果生成。在原始 Encoder-Decoder Transformer 里，Decoder 还有 cross-attention 去读 Encoder 输出；但 GPT 这种 decoder-only 没有 encoder，所以也没有 cross-attention。\nQ3 对。更完整说法：GPT 用 decoder-only 是因为预训练目标是 next-token prediction，天然要求当前位置只能依赖历史 token。Decoder-only 结构简单、训练目标和推理方式一致，很适合规模化生成。\nQ6 小修：top-k 不是“按照概率从高到低选择”，而是只保留概率最高的 k 个 token，然后在这 k 个里面重新归一化并采样。top-p 是保留从高到低累计概率达到 p 的最小候选集合，然后重新归一化并采样。你说的“小于 p”接近，但通常是“直到累计概率达到/超过 p”。\n","date":"2026-05-08","externalUrl":null,"permalink":"/notes/llm02-transformer/","section":"知识笔记","summary":"transformer # transformer是在这篇attention is all you need中提出来的。\n","title":"LLM02 Transformer","type":"notes"},{"content":" attention # 注意力机制，最早是在机器翻译论文**Neural Machine Translation by Jointly Learning to Align and Translate**中提出来的，他的核心是，用一个东西产生的query，去key/value中查询需要的东西。在上述论文中encoder-decoder attention的结构中。\n1Q来自于decoder 2K,V来自于encoderdecoder 当前正在生成目标语言词，它用自己的 query 去源语言句子的 encoder 表示里查找相关信息。\n只要Q、K、V来自于不同的地方，就是attention机制。\nattention的本质 # 实际上attention就是根据相关性对信息进行分配权重，在加权汇总。\n他不是让模型一整个平均的去看信息，而是让模型知道什么更重要，什么没那么重要，重要的多看一点。\n数学上就是这样表示：\n11. 用 Query 和 Key 算相关性分数 2 score = QK^T 32. 用 softmax 把分数变成权重 4 weights = softmax(score) 53. 用这些权重对 Value 做加权求和 6 output = weights · V self-attention # 区别于attention，自注意力机制的Q、K、V都是来自于同一个source。\n$$ Q=X W_q \\\\ K=X W_k \\\\ V=X W_v $$上面公式中的X就是source，Q、K、V都是从X得到的。\nself-attention的本质 # 让序列中的每个位置，根据自身内容，动态地从同一序列的所有位置中取信息。\n根据上面计算得到的Q、K、V，让每一个token的Q和其他所有的token的K都计算一遍相似度\n$$ score = Q K^T \\sqrt{d_k} $$再根据权重值，得到输出：\n$$ output=softmax(score)V $$上述公式是论文attention is all you need中的，其中的$d_k$分别是是K的维度（dimension）。作用是防止计算得到的score过于大，导致经过softmax之后过分尖锐（一个位置的权重无限接近于1，其余位置无限接近于0，训练效果差），或者说，除以$d_k$是为了防止进入softmax的饱和区，导致梯度消失。神经网络更新参数是需要根据梯度变化来更新的。\n$$ \\frac{\\partial p_i}{\\partial z_i} = p_i(1 - p_i) $$ causal self attention # 是一种带因果罩的self-attention。即判断当前token是否能看见，未来token，比如我 喜欢 大 模型 对于喜欢这个token，就无法看见大 模型这两个token，在处理喜欢这个token的时候，就会给他后面的token添加一个causal mask，把未来的attention score设置为-inf，因为此处的softmax是0。\n对于生成式（GPT）的任务，通常需要从左往右输出下一个token，如果在训练时没有遮蔽未来token，相当于就是让模型提前知道了答案，训练loss很好看，但是模型能力并没有得到训练，所以对于GPT这种自回归语言模型必须要有causal mask。\n而对于理解型任务，比如情感分析，文本填空，则需要双向self attention，要理解整句话，比如下面的例子\n1这部电影前半段无聊，但结尾非常震撼。判断情感时，“无聊”应该能看到后面的“但结尾非常震撼”，否则理解会偏。BERT 这类模型就通常用普通双向 self-attention，可以看左右两边。\n添加位置编码 # self-attention虽然考虑了所有的输入变量，但是并没有考虑每个变量处于序列中的位置。\n比如，我 爱 你和你 爱 我就是两组序列，原本的self- attention只关心他们每个词的相关性，不在乎顺序，但很明显这两组序列想表达的意思是绝对不一样的。\n于是便有了添加位置编码来明确每个输入变量（token）的位置。图片中的e就是位置编码。\n注意：位置编码的计算不是直接根据token的位置1，2，3，4得到的，主要有两种逻辑，一种是根据公式计算，像attention is all you need中的sin/cos位置编码就是通过公式计算到的；另一种是可学习的位置编码，比如：$P_{position} ∈ R^{(max_{len} × d_{model})}$，训练不光得到Wq、Wk、Wv，还会得到这个位置编码的计算方式。 multi-head attention # 是指不是指用一套Q、K、V来去看上下文，而是用多套Q、K、V去看。\n比如有8个head：\n$$ head_1: Wq_1, Wk_1, Wv_1\\ head_2: Wq_2, Wk_2, Wv_2\\ \u0026hellip;\\ head_8: Wq_8, Wk_8, Wv_8\\\n$$\n对于每个head，都回去计算一遍output：\n$$ Q_i = XWq_i\\\\ K_i = XWk_i\\\\ V_i = XWv_i\\\\ \\\\ head_i = softmax(Q_i K_i^T \\sqrt{(d_k)})V_i\\\\ $$再把每个head都concat起来。\n$$ concat = [head_1; head_2; \u0026hellip;; head_h] \\ output = concat * W_o\n$$\n最终的到新的输出。\n为什么要有多头注意力：因为一个 attention head 的表达能力有限。多头相当于让模型同时提出不同问题。 比如：小明把苹果放进书包，因为它很甜。对于不同的head就会关注不同的关系\n1head 1：关注“它”指代谁 2head 2：关注形容词“甜”和名词的关系 3head 3：关注局部相邻词 4head 4：关注主谓宾结构下图中的h就是head的数量。\n对于多头注意力机制，训练得到的参数在前面的基础上，又增加了$W_o$，它负责把各个 head 看到的东西怎么合并。\n$$ W_o ∈ R^{(h * d_v × d_{model})}\n$$\ngraph LR A---\u003eB[attention] A---\u003eC[self-attention] C---\u003eD[single-head] C---\u003eE[multi-head] D---\u003eF[normal] D---\u003eG[causal] E---\u003eH[normal] E---\u003eI[causal] test： # Q1：Q、K、V 分别来自哪里？为什么不是直接用输入向量两两算相似度？\nA1：Q、K、V都是通过对embedding的数据分别其乘上其对应的权重系数得到的，比如Q=Wq*X；因为attention机制就是为了根据相关性对信息来分配权重，而直接两两相乘，忽略了相关性，效果不好。\nQ2：attention score 为什么要除以sqrt(d_k)\nA2：因为如果不除去这个K的维度开方，权重值会偏大，导致softmax容易进入饱和区，从而导致梯度消失，而神经网络的训练都是根据梯度来变化来更新参数的。\nQ3：softmax 后的 attention weights 表示什么？\nA3：每个token的Q和K求得的相似度，也就是这个token在全文中的权重。\nQ4：self-attention 相比 RNN/CNN，核心优势和代价分别是什么？\nA4：参见Self-Attention、RNN、CNN 核心对比\nQ5:causal self-attention 和普通 self-attention 差在哪里？ A5:causal self-attention 没有学到\nA1:小修正：不是“直接两两相乘忽略了相关性”，直接用输入向量做相似度其实也能算相关性，但表达能力弱。引入Wq/Wk/Wv的意义是让模型学会三种不同角色：\nQ：当前 token 想找什么信息 K：每个 token 能被别人匹配的特征 V：真正被加权汇总的信息内容 A3：Q3 需要再精确一点。softmax 后的 attention weights 表示：对某一个 query token 来说，它应该从各个 key/value token 那里取多少信息。不是“这个 token 在全文中的权重”，而是“这个 token 看其他 token 的分配比例”。\nA4：补上：\n相比 RNN：self-attention 可以并行处理序列，而且任意两个 token 的交互路径更短；RNN 要一步步传递，长距离依赖容易衰减。 相比 CNN：self-attention 可以直接建模任意位置之间的关系；CNN 依赖卷积核和层数扩大感受。 代价：标准 self-attention 的计算和显存复杂度是O(n^2)，序列越长越贵。 A5：causal self-attention 是 decoder / 自回归生成里用的。它和普通 self-attention 的区别是：当前 token 只能看自己和它左边的 token，不能看未来 token。\n比如句子：\n我 喜欢 大 模型 生成“喜欢”时，只能看“我”和“喜欢”，不能偷看后面的“大 模型”。实现上会加一个 causal mask，把未来位置的 attention score 设成-inf，softmax 后权重就是 0。\n","date":"2026-05-08","externalUrl":null,"permalink":"/notes/llm01-self-attention/","section":"知识笔记","summary":"attention # 注意力机制，最早是在机器翻译论文**Neural Machine Translation by Jointly Learning to Align and Translate**中提出来的，他的核心是，用一个东西产生的query，去key/value中查询需要的东西。在上述论文中encoder-decoder attention的结构中。\n","title":"LLM01 Self Attention","type":"notes"},{"content":"这里写日记\u0026hellip; 以后的日记还是在appflowy上面更新了，但是他的跨设备功能很方便，但是我现在还没找到导出markdown的按钮，所以现在不太能连载到我的博客网站上面了\n取消了一个appflowy，fuck，因为他不但没有导出markdown function，而且还没有ai接入功能，在他足够完善之前，我都会使用obsidian的sync方案。虽然有点贵，一个月要37块钱左右，就当成知识付费了，但是部署appflowy的经历还是有不少可以总结的。\n最近部署了一下 appflowy 在我的火山云服务器上，感觉虽然有点麻烦但是还是有点意思的~(¯▽¯)\n部署遇到的问题 # dns无法解析域名 # 我在给阿里云的域名后台添加了appflowy.somnus.top的解析后，发现在服务器端还是没办法解析到这个域名的ip，\n1root@iv-yef9e14c8wxjd1vkt7di:~/AppFlowy-Cloud# nslookup appflowy.somnus.top 8.8.8.8Server:\t8.8.8.8Address:\t8.8.8.8#53** server can\u0026#39;t find appflowy.somnus.top: NXDOMAIN后台在claude一步步帮助下，我通过这个指令。\n1root@iv-yef9e14c8wxjd1vkt7di:~/AppFlowy-Cloud# nslookup -type=NS somnus.top 8.8.8.8Server: 8.8.8.8Address: 8.8.8.8#53Non-authoritative answer:somnus.top nameserver = zariyah.ns.cloudflare.com.somnus.top nameserver = alan.ns.cloudflare.com.Authoritative answers can be found from:root@iv-yef9e14c8wxjd1vkt7di:~/AppFlowy-Cloud#才知道了原来我的阿里云已经把解析的权力给了cloudflare。\n因为这个域名的主域名是用于博客网站的搭建，即somnus.top，而为了便宜，这个博客网站是我通过github actions搭建的，为了方便国内能比较快的访问这个博客网站，我便把解析权给了cloudflare。\n于是我在cloudflare后台，在添加了一条新的A解析，这个问题就解决了。\n其实这个问题，之前就遇到过，在我搭建vaultwarden的时候，就遇到过，但是这次又忘记😅了。\n部署体验 # 整体体验下来，效果还是很好的，感觉同步也很流畅，不再依赖于国外的服务器，ios端也不会出现报错。\n但是最大的问题就是两个\n无法本地使用deepseek或者其他api # appflowy原生支持的是openai的api调用，来实现其ai功能。但是openai很贵！！！于是我想着使用deepseek的api调用来实现ai功能，发现并不能原生支持，在deploy.env中，根本没有baseurl的配置项\n1AI_OPENAI_API_KEY=# If no summary model is provided, there will be no search summary when using AI search.AI_OPENAI_API_SUMMARY_MODEL=然后去这个项目的issues里面找，发现早在24年就有人提出了，要添加其他模型支持的fr。\n然后我fork了开源的appflowy和appflowy_cloud两个项目到本地，问codex发现ai功能是在appflowy_ai这个组件中执行的。而这个组件是一个docker的images，并没有开源出来。\n😡草了，没招了，只能等官方推进这个吧，或者等官方开源这个组件。详情可以关注一下这个issues的讨论。\n无法单个页面导出markdown # 具体bu za\n无法单个页面导出markdown # 具体不再多说了。\n我会继续找一些其他的可以方便部署的类notion，在此之前，我先用obsidian sync了。\n","date":"2026-05-06","externalUrl":null,"permalink":"/diary/2026-05-06/","section":"日记","summary":"这里写日记… 以后的日记还是在appflowy上面更新了，但是他的跨设备功能很方便，但是我现在还没找到导出markdown的按钮，所以现在不太能连载到我的博客网站上面了\n","title":"2026-05-06","type":"diary"},{"content":"临时写一篇日记，昨天晚上看了一篇koji关于阿里百炼技术负责人的于文渊的视频播客，略有感想。\n总结播客 # 于文渊提到，\nai的应用场景已经从闲聊转向了生产力的场景，从而带动了高质量token消耗量指数级提升。 阿里云百炼的核心使命之一是实现算力资源的最优化配置，确保每一块 GPU 都能被物尽其用 对于计算机专业的学生，他建议应利用 AI 提升效率，但核心竞争力在于能够识别 AI 产出的潜在缺陷，坚守那 1% 的深度判断力 算力短缺如同工业领域的“石油”匮乏，中国 AI 发展的关键在于算力供给的稳定性与自主可控程度 个人思考 # 其实其他方面我也没怎么关注，但是我比较关心的就是，作为cs学生，如何在ai时代下正确的处理ai辅助接替工作的情况😅，他给了比较明确的观点，就是不要让ai去完全地接替你的工作。 他在播客中举了一个张文宏的例子，如果你作为一个资深的医生，去使用ai来辅助你工作，这没问题~但是你如果作为小白医生，第一天就开始使用ai来做一些诊断，这样就完全乱套了，后续ai如果除了什么问题，就也根本没有什么判断的能力了。 我觉得这个例子举得很好了，我在享受ai编程带来的便利的同时，也忽略了他的危害，他让我在脱离ai的情况下，几乎一个简单的程序都写不出来😇，这些是值得警惕的。\n","date":"2026-05-04","externalUrl":null,"permalink":"/diary/2026-05-04/","section":"日记","summary":"临时写一篇日记，昨天晚上看了一篇koji关于阿里百炼技术负责人的于文渊的视频播客，略有感想。\n","title":"2026-05-04","type":"diary"},{"content":"","date":"2026-05-04","externalUrl":null,"permalink":"/tags/thinking/","section":"Tags","summary":"","title":"Thinking","type":"tags"},{"content":" rust学习 # 今天的rust的学习主要是学了trait，我原本对trait的印象就是一个放在#[derive()]里面的，比如增加了Display或者Debug的trait之后，就可以直接在println里面打印结构体。\n我今天主要学的就是重载运算符、Drop和trait的特性。简单总结一下\ntrait # trait是什么，顾名思义，trait的中文是特征，即一种定义共享行为的机制，不管是什么数据类型，只要定义了这个trait，就一定要完成某个共享行为。比如说：Display、Debug、Drop\u0026hellip;..对于绝大多数数据类型，这些trait都是满足的。 为什么要有trait？我自己总结下来有三点原因：\n代码复用： # 对于任何数据类型，他的同一个trait都可以有自己的实现方法，但是如果该数据类型没有自定义实现方法，可以通过trait得到一个默认的方法。\n1trait Greet { 2 fn name(\u0026amp;self) -\u0026gt; String; 3 fn greet(\u0026amp;self) -\u0026gt; String { // 默认实现 4 format!(\u0026#34;Hello, {}!\u0026#34;, self.name()) 5 } 6} 泛型约束： # 让函数接受\u0026quot;任何实现了某 trait 的类型\u0026quot;，实现静态多态。\n1fn make_sound\u0026lt;T: Animal\u0026gt;(animal: \u0026amp;T) { 2 println!(\u0026#34;{} says {}\u0026#34;, animal.name(), animal.speak()); 3} 4// 或用 impl Trait 语法（更简洁） 5fn make_sound(animal: \u0026amp;impl Animal) { ... }编译器在编译之后就单态化他了。\n动态分发： # 使用dyn trait实现运行时的多态，可以在box里面存放不同的类型。\n1let animals: Vec\u0026lt;Box\u0026lt;dyn Animal\u0026gt;\u0026gt; = vec![ 2 Box::new(Dog), 3 Box::new(Cat), 4]; 5for a in \u0026amp;animals { 6 println!(\u0026#34;{}\u0026#34;, a.speak()); // 运行时决定调用哪个实现 7} dyn # 具体说一下trait的动态分发的例子：\n1fn main() { 2 let rn = 0.63; 3 println!(\u0026#34;{}\u0026#34;, random_animal(rn).noise()); 4 println!(\u0026#34;helloworld\u0026#34;) 5} 6 7struct Sheep {} 8struct Cow {} 9trait Animal { 10 fn noise(\u0026amp;self) -\u0026gt; \u0026amp;\u0026#39;static str; 11} 12impl Animal for Sheep { 13 fn noise(\u0026amp;self) -\u0026gt; \u0026amp;\u0026#39;static str { 14 \u0026#34;mie ~~~\u0026#34; 15 } 16} 17impl Animal for Cow { 18 fn noise(\u0026amp;self) -\u0026gt; \u0026amp;\u0026#39;static str { 19 \u0026#34;mou ~~~\u0026#34; 20 } 21} 22fn random_animal(rn: f64) -\u0026gt; Box\u0026lt;dyn Animal\u0026gt; { 23 if rn \u0026gt; 0.5 { 24 Box::new(Sheep {}) 25 } else { 26 Box::new(Cow {}) 27 } 28}上面代码中，对于random_animal的返回，就使用了动态分发，不需要提前预设好类型，不需要指定是Sheep还是Cow。\n","date":"2026-04-30","externalUrl":null,"permalink":"/diary/2026-04-30/","section":"日记","summary":"rust学习 # 今天的rust的学习主要是学了trait，我原本对trait的印象就是一个放在#[derive()]里面的，比如增加了Display或者Debug的trait之后，就可以直接在println里面打印结构体。\n","title":"2026-04-30","type":"diary"},{"content":"最近刘总分配了一个新任务，就是从抖店后台抓取抖店的订单数据，保存到本地的excel，还是有所经验可以总结的\n先介绍方案，先通过影刀来抓取网页数据，并保存到本地，在将其本地数据通过调用大模型进行清理，再通过python将其写入到中excel。\n自动获取数据 # 为什么使用影刀 # 相较于影刀，我更多关注了哪些原生支持cli和开源的方案，一方面，支持cli就可以通过agent来自动化获取数据；另一方面，开源方案通常来说本地部署是不需要钱的。 但是后来我在试着根据这个视频来通过claude code调用playwrightcli，但是效果非常差，经常莫名其妙要求人工验证，也不知道哪里出问题了，之后有时间我准备在codex上再试试。 影刀使用还是很方便的，全是拖动节点，手动捕获目标区域。整个就是模拟人类点击滚动等操作，很不容易被封禁。关于费用方面，我目前也没发现他有什么收费的点，好像是多人合作使用一个的时候要付费，等于免费😆\n其实可以看到，我这个获取数据还是不是直接整个页面获取的，而是分成了两个获取的步骤，第一个获取相似元素：因为每个商品卡没办法捕获为整体， 而每个商品的标题栏，也就是订单编号和下单时间这一栏，可以捕获，于是我对每个订单的标题栏都采用了获取相似元素列表，最终保存结果为order*heads.csv，这个数据是相对==*干净整洁_==的 但是效果还是不够好，还是会识别出一些乱的文字，如下图 于是我最终还是决定调用大模型来分析和处理这些数据。输入的文件就是这个heads，和fullpage的文件。\n本地大模型调用 # 我原本是在使用fastgpt来处理这个数据的，因为fastgpt可以显式的制定大模型的提示词，而且之前那个净水客服我也配置好了相应的大模型供应商。但是后来发现搞来搞去，最后就一个节点😅，于是fastgpt就显得没什么很大的必要了。我最后决定使用openai库来调用大模型处理，话说这应该是我第一次通过代码来本地调用大模型。先看一下main函数：\n1def main() -\u0026gt; int: 2 3log(\u0026#34;加载环境变量\u0026#34;) 4 5load_dotenv() 6parser = argparse.ArgumentParser(description=\u0026#34;Call DashScope to generate output.json\u0026#34;) 7parser.add_argument(\u0026#34;--prompt\u0026#34;, default=\u0026#34;prompt.txt\u0026#34;, help=\u0026#34;prompt file path\u0026#34;) 8parser.add_argument(\u0026#34;--heads\u0026#34;, default=\u0026#34;data/order_heads.csv\u0026#34;, help=\u0026#34;order heads csv path\u0026#34;) 9parser.add_argument(\u0026#34;--full\u0026#34;, default=\u0026#34;data/order_full.txt\u0026#34;, help=\u0026#34;full order text path\u0026#34;) 10parser.add_argument(\u0026#34;--out\u0026#34;, default=\u0026#34;data/output.json\u0026#34;, help=\u0026#34;output JSON path\u0026#34;) 11parser.add_argument(\u0026#34;--model\u0026#34;, default=os.getenv(\u0026#34;DASHSCOPE_MODEL\u0026#34;, DEFAULT_MODEL)) 12parser.add_argument(\u0026#34;--base-url\u0026#34;, default=os.getenv(\u0026#34;DASHSCOPE_BASE_URL\u0026#34;, DEFAULT_BASE_URL)) 13parser.add_argument(\u0026#34;--api-key\u0026#34;, default=os.getenv(\u0026#34;DASHSCOPE_API_KEY\u0026#34;)) 14parser.add_argument( 15\u0026#34;--no-json-mode\u0026#34;, 16action=\u0026#34;store_true\u0026#34;, 17help=\u0026#34;do not send response_format=json_object to the model API\u0026#34;, 18) 19args = parser.parse_args() 20if not args.api_key: 21print(\u0026#34;缺少 DASHSCOPE_API_KEY。请先创建 .env，或用 --api-key 传入。\u0026#34;, file=sys.stderr) 22return 2 23log(\u0026#34;开始生成 output.json\u0026#34;) 24result = call_model( 25prompt_path=Path(args.prompt), 26order_heads_path=Path(args.heads), 27order_full_path=Path(args.full), 28model=args.model, 29base_url=args.base_url, 30api_key=args.api_key, 31use_json_mode=not args.no_json_mode, 32) 33out_path = Path(args.out) 34log(f\u0026#34;写入结果文件: {out_path}\u0026#34;) 35out_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding=\u0026#34;utf-8\u0026#34;) 36order_count = len(result.get(\u0026#34;orders\u0026#34;, [])) if isinstance(result, dict) else 0 37log(f\u0026#34;已生成: {out_path}\u0026#34;) 38log(f\u0026#34;订单数量: {order_count}\u0026#34;) 39return 0首先这个main函数很明显的一点就是使用了argparser来解析命令行，分别获取数据文件位置，大模型相关信息（base_url、model、dashborad、api，promot），然后调用call_model这个函数来调用大模型。 在call_model函数中，核心就这些\n1log(f\u0026#34;初始化模型客户端: model={model}, base_url={base_url}\u0026#34;) 2 3client = OpenAI(api_key=api_key, base_url=base_url) 4 5kwargs: dict[str, Any] = { 6 7\u0026#34;model\u0026#34;: model, 8 9\u0026#34;messages\u0026#34;: [ 10 11{ 12 13\u0026#34;role\u0026#34;: \u0026#34;system\u0026#34;, 14 15\u0026#34;content\u0026#34;: \u0026#34;你是订单文本结构化助手。只返回严格 JSON，不要返回 Markdown 或额外说明。\u0026#34;, 16 17}, 18 19{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: user_message}, 20 21], 22 23\u0026#34;temperature\u0026#34;: 0, 24 25} 26 27if use_json_mode: 28 29kwargs[\u0026#34;response_format\u0026#34;] = {\u0026#34;type\u0026#34;: \u0026#34;json_object\u0026#34;} 30 31 32 33log(\u0026#34;开始请求大模型，等待返回...\u0026#34;) 34 35start = time.perf_counter() 36 37response = client.chat.completions.create(**kwargs) 38 39elapsed = time.perf_counter() - start 40 41log(f\u0026#34;模型已返回，耗时 {elapsed:.1f} 秒\u0026#34;)然后再对这个输出的json进行一些格式检查，就直接保存到本地了。 输出的json文件如下： 写入excel # 要求写入的表格如下： xlsx文件本质是一个压缩包，把不同的sheet压缩到一块。通过python的zipfile可以对xlsx文件进行解压并读取，写入完成后，再通过zipfile对其重新压缩。 对于文件写入，是通过xml.etree.ElementTree这个模块来获得的，展开后的xlsx，本质都是xml结构，即openxml协议。 通过手动查找、增加和修改 XML 标签（例如表示行的 \u0026lt;row\u0026gt; 和表示单元格的 \u0026lt;c\u0026gt; 以及表示值的 \u0026lt;v\u0026gt;）来实现对工作表内容的编辑。 %% 该说不说，在此之前我对xlsx一直都有刻板印象，是一个微软（肯定不是）的封闭的打开很麻烦的一种文件格式，没想到竟然内部也是朴实无华的。 %% 通过这样一套逻辑，也可以成功的把数据写入到指定的行和列。\ngraph TD a[开始] --定时启动--\u003e b[影刀] b--数据--\u003ec[大模型] c--\u003ed[写入xlsx] 生活 # 最近把公司配的macbook熟络了一下，真香啊，感觉这个屏幕看着就很舒服，其实这个屏幕也不是高刷屏，但好像是什么hdr，反正看着就是很舒服。 除此以外，macos的生态也很好，很多我的linux上没有的软件，macos都支持。 希望以后能有钱买这个电脑\n","date":"2026-04-29","externalUrl":null,"permalink":"/diary/2026-04-29/","section":"日记","summary":"最近刘总分配了一个新任务，就是从抖店后台抓取抖店的订单数据，保存到本地的excel，还是有所经验可以总结的\n","title":"2026-04-29","type":"diary"},{"content":"","date":"2026-04-29","externalUrl":null,"permalink":"/tags/automation/","section":"Tags","summary":"","title":"Automation","type":"tags"},{"content":"","date":"2026-04-21","externalUrl":null,"permalink":"/tags/ssh/","section":"Tags","summary":"","title":"Ssh","type":"tags"},{"content":"","date":"2026-04-21","externalUrl":null,"permalink":"/categories/tutorial/","section":"分类","summary":"","title":"Tutorial","type":"categories"},{"content":"","date":"2026-04-21","externalUrl":null,"permalink":"/tags/zip/","section":"Tags","summary":"","title":"Zip","type":"tags"},{"content":"我在没有这个台式机之前只有一个带集显的笔记本，所以之前的训练任务只能通过租服务器来训练，不可避免的去学一下操作远程服务器的指令。避免每次都要google或者问ai，于是写成这篇博客。 感觉这样的操作就像现在很火的一个词:skill \u0026#x1f604;，总结成经验方便以后调用。\nssh连接 # 首先是连接\n1ssh -p 44012 root@connect.bjb2.seetacloud.com然后输入yes，再输入密码。 这个很简单，也没有什么好说的。\n从远程服务器复制 # scp指令 # 这个是最常用的从远程复制文件到本地的指令。\n1scp -P 8888 用户名@服务器IP:远程文件绝对路径 本地保存路径同样对于上面那个服务器地址。想要复制他的文件或者文件夹就执行\n1scp -P 44012 -r root@connect.bjb2.seetacloud.com:/root/autodl-fs/middlebury ~/work/bishe/对于一个文件夹，需要加上-r。 但是这个指令的优点也是唯一的优点就是用法简单；缺点很多：不支持断点续传，不支持效率低。 sftp指令 # 特点：交互式操作、类似FTP的操作 1sftp user@remote_host 2# 进入 sftp 交互界面后： 3sftp\u0026gt; cd /logs/nginx/ # 切换远程目录 4sftp\u0026gt; ls -lh # 查看远程文件大小 5sftp\u0026gt; get access.log.1.gz # 下载指定文件 6sftp\u0026gt; exit # 退出 优点：操作方便，直观；支持断点续传。 缺点：传输效率一般。 rsync指令 # 基于增量传输算法，是目前公认的最强的文件同步工具。 普及率也还行，目前大部分主流linux发行版都会预装rsync,比如unbunt,centos,fedora。 rsync最常用的参数组合就是-avz\n-a(archieve):保留权限，软链接，时间戳等属性。\n-v(verbose):显示详细进度。\n-z(compress):传输时压缩节约流量，传的更快。 如果需要添加服务器端口信息，则需要像上面一个-e \u0026ldquo;-P 端口号\u0026rdquo; 在rsync中，源路径结尾是否加斜杠区别很大:\nmy_site/（带斜杠）：同步目录下的内容。\nmy_site（不带斜杠）：同步目录本身及其内容。\n","date":"2026-04-21","externalUrl":null,"permalink":"/p/%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9F%BA%E7%A1%801/","section":"技术博客","summary":"我在没有这个台式机之前只有一个带集显的笔记本，所以之前的训练任务只能通过租服务器来训练，不可避免的去学一下操作远程服务器的指令。避免每次都要google或者问ai，于是写成这篇博客。 感觉这样的操作就像现在很火的一个词:skill 😄，总结成经验方便以后调用。\n","title":"服务器基础1","type":"posts"},{"content":"这里收纳更完整的技术输出：项目复盘、系统教程、实验报告和复杂问题排查。\n","date":"2026-04-21","externalUrl":null,"permalink":"/posts/","section":"技术博客","summary":"完整的项目复盘、系统教程和可对外分享的技术长文。","title":"技术博客","type":"posts"},{"content":"","date":"2026-04-20","externalUrl":null,"permalink":"/tags/cachyos/","section":"Tags","summary":"","title":"Cachyos","type":"tags"},{"content":"前言： 刚刚入职一周左右，我现在也算在玄武安定下来了，于是我便让我家里人把我寒假组装的台式机从老家寄过来，然后我还买了一块 1TB 的固态硬盘 \u0026#x1f4be;，专门用于台式机的 Linux 系统。 最近这段时间，Linux 系统也是经历了频繁更换 \u0026#x1f605; -\u0026gt; ubuntu -\u0026gt; archlinux -\u0026gt; fedora -\u0026gt; cachyos。最终决定长期使用的就是 CachyOS \u0026#x1f389;。\n简要介绍 \u0026#x1f31f; # CachyOS 是由 CDN77 和 CLOUDFLARE 赞助的、基于 Arch Linux 的开源 Linux 发行版，主打的特点是极致的性能 \u0026#x1f680;！它的每个封装都编译了 x86-64-v3、x86-64-v4 和 Zen4 指令集以及 LTO。核心封装还会获得额外的 PGO 和 BOLT 优化——完全无需手动重建。 为了方便能释放出我电脑的所有性能 \u0026#x1f4aa;，于是我便选择了 CachyOS，不太喜欢像 Arch Linux 那种完全自定义，实在是太麻烦了 \u0026#x1f622;\n安装 \u0026#x1f527; # 安装直接可以看 shorin 的 wiki。 通过这个连接访问 \u0026#x1f517; Shorin-ArchLinux-Guide/wiki/CachyOS 我就写一个注意的点。我在我的 HP 笔记本上装双系统，按照这个流程几乎一点问题都没有（原本别人说的在 ISO 中要提前改源的点似乎已经被修复了 \u0026#x2705;）。 但是在我的台式机 \u0026#x1f5a5;\u0026#xfe0f; 上，在两个不同的硬盘上安装双系统就出现问题了 \u0026#x26a0;\u0026#xfe0f;。\n问题 1 \u0026#x2753; # 表现 \u0026#x1f440; # 在配置安装的时候会发现选择引导 (grub) 界面会和 shorin 的教程中不太一样，只剩下两个选择，就是 grub 和另一个什么，此时就该发现不对了 \u0026#x1f645;。然后在后面安装的过程中也会出现报错，直接终止安装 \u0026#x274c;。\n1The bootloader could not be installed. The installation command \u0026lt;pre\u0026gt;grub-install --target=i386-pc --recheck --force /dev/nvme0n1\u0026lt;/pre\u0026gt; returned error code 1. 解决 \u0026#x1f6e0;\u0026#xfe0f; # 这个问题其实很好解决。在安装的时候，我起初没有注意到 bootloader 的位置。在选择分区的时候左下角有一个选择 bootloader，将这个要设置成和要装 CachyOS 的盘一致 :disk:。此后就安装成功了 \u0026#x1f389;，但紧接着就是第二个问题。\n问题 2 \u0026#x2753; # 表现 \u0026#x1f440; # 按照 CachyOS Hello 的指引，选择了 reboot，我们会发现电脑直接进入了 Windows 而非 grub \u0026#x1f62d;。 根据网上的说法，可能是主板 BIOS 启动设置的问题，比如什么 secure boot 模式。这一部分问题我全部都排查过了，可以从 shorin 的 wiki 中提前做好设置。 解决 \u0026#x1f6e0;\u0026#xfe0f; # 我首先去主板里把启动项设置成我装 Linux 的固态硬盘，然后才可以正常进入 grub。但是问题是没能够在 grub 中找到 Windows 的启动选项 \u0026#x1f4ad;。后来逐渐摸排，才发现问题出现在主板上：主板处于 UEFI 和 Legacy 的兼容模式 (CSM)，导致开机会自动进入主板的兼容选择模式，此时便会根据在 BIOS 中的选择来启动，而 grub 没办法兼容两种启动方式。如果你强行在 grub 里面添加 Windows 的启动项，就会出现下面的报错情况： 为了解决这个问题，我们直接把主板的 CSM 兼容模式关闭 \u0026#x1f6ab;，然后重新安装一遍，便大功告成 \u0026#x1f970; \u0026#x1f38a;!\n问题 3 (可能存在) \u0026#x26a0;\u0026#xfe0f; # 表现 \u0026#x1f440; # 由于网络原因，安装的下载过程奇慢无比 \u0026#x1f40c;。\n解决 \u0026#x1f6e0;\u0026#xfe0f; # 手动把源换成中国的源 \u0026#x1f1e8;\u0026#x1f1f3;。\n1# 切换目录 2cd /etc/pacman.d/ 3 4# 替换CachyOS本体源为中科大国内源 5sudo tee cachyos-mirrorlist \u0026lt;\u0026lt;EOF 6Server = https://mirrors.ustc.edu.cn/cachyos/repo/\\$arch/\\$repo 7EOF 8 9sudo tee cachyos-v3-mirrorlist \u0026lt;\u0026lt;EOF 10Server = https://mirrors.ustc.edu.cn/cachyos/repo/\\$arch_v3/\\$repo 11EOF 12 13sudo tee cachyos-v4-mirrorlist \u0026lt;\u0026lt;EOF 14Server = https://mirrors.ustc.edu.cn/cachyos/repo/\\$arch_v4/\\$repo 15EOF 16 17# 替换Arch Linux基础源为中科大国内源 18sudo tee mirrorlist \u0026lt;\u0026lt;EOF 19Server = https://mirrors.ustc.edu.cn/archlinux/\\$repo/os/\\$arch 20EOF禁用自动测速：\n1sudo sed -i \u0026#39;1i exit 0\u0026#39; /etc/calamares/scripts/update-mirrorlist 配置 \u0026#x2699;\u0026#xfe0f; # 进入 CachyOS 后，主要可以根据 shorin 的教程设置几个基础选项，此外你还可以进行以下操作：\n安装 Clash Verge \u0026#x1f310; # 第一步也是最重要的一步 \u0026#x2757;，先准备好科学上网的环境。在 AUR 中可以找到 clash-verge-rev-bin \u0026#x1f50d;，但是由于源头是在 GitHub，所以下载速度也是奇慢无比 \u0026#x1f422;。我们可以通过代理方式，先提前下载好 clash-verge-rev 的 Deb 安装包，然后执行一次 paru 安装指令。\n1paru -S clash-verge-rev-bin让它生成文件夹： \u0026#x1f4c2;\n1cp ~/Downloads/Clash.Verge_2.4.7_amd64.deb ~/.cache/paru/clone/clash-verge-rev-bin/clash-verge-rev-2.4.7-x86_64.deb然后把下载好的安装包丢进 paru 的缓存目录里，重新执行一遍安装即可。 \u0026#x2728;\n从 Fish 换到 Zsh \u0026#x1f41a; # fish虽然也很好用，但是存在一些支持性问题，有些指令会不兼容，而zsh在比bash更好用以外还能支持几乎所有的bash语法。所以我们要把cachyos默认的fish切换成zsh。 首先可以通过这个命令来查看当前使用的shell。\n1echo $SHELL如果没有安装zsh,先安装zsh\n1sudo pacman -S zsh然后通过下面这个命令来切换shell\n1chsh -s /usr/bin/zsh然后直接关机重启，不要注销，感觉没用\u0026#x1f36d;。\n","date":"2026-04-20","externalUrl":null,"permalink":"/p/cachyos%E5%AE%89%E8%A3%85/","section":"技术博客","summary":"前言： 刚刚入职一周左右，我现在也算在玄武安定下来了，于是我便让我家里人把我寒假组装的台式机从老家寄过来，然后我还买了一块 1TB 的固态硬盘 💾，专门用于台式机的 Linux 系统。 最近这段时间，Linux 系统也是经历了频繁更换 😅 -\u003e ubuntu -\u003e archlinux -\u003e fedora -\u003e cachyos。最终决定长期使用的就是 CachyOS 🎉。\n","title":"Cachyos安装","type":"posts"},{"content":"","date":"2026-04-20","externalUrl":null,"permalink":"/tags/grub/","section":"Tags","summary":"","title":"Grub","type":"tags"},{"content":"","date":"2026-04-20","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"2026-04-17","externalUrl":null,"permalink":"/tags/markdown/","section":"Tags","summary":"","title":"Markdown","type":"tags"},{"content":"最近正在准备写本科毕业设计论文，不想用微软的word写，因为感觉不够极客 \u0026#x1f627; ，也不想使用LaTex，因为LaTex太笨重了，编译速度太慢了，在线服务overleaf又是收费的（帮黄学长报销这个来着，好像一个月要三百多 🙀） 在网上搜罗搜罗发现了typst，一个基于rust内核的开源的标记语言排版系统，速度非常快，功能我觉得的也足够强（公式什么的都能很好地显示），同时我在他的模板库也找到了其他大学的毕业论文模板（nju），于是基于这个模板，我便衍生做一个swjtu的版本，最后，感谢nju-lug。\n基础介绍 # 先简单介绍一下typst，是一款可用于出版的可编程标记语言，拥有变量、函数与包管理等现代编程语言特点，同时又注重于科学写作领域，与LaTex相似。\n语法简洁：上手难度与markdown相当，文本的源码阅读性很高 编译速度快：typst用的是rust编写的，即typ(esetting+ru)st，运行平台是WASM, 环境搭建简单：不需要像LaTex折腾几个G的开发环境，可以在Web运行，还可以用vscode安装插件开发。 Typst 简明语法指南 # Typst 是一款现代、高效的排版系统，旨在提供比 LaTeX 更简单的语法和更快的渲染速度。其语法主要分为：标记模式 (Markup)、数学模式 (Math) 和 脚本模式 (Scripting)。\n基础文本排版 (Markup Mode) # 标记模式用于文档的正文结构，类似于 Markdown。\n功能 语法示例 说明 标题 = 一级标题, == 二级标题 = 越多层级越深，等号后需空格 加粗 *加粗内容* 使用星号包裹 斜体 _斜体内容_ 使用下划线包裹 代码块 ` `行内代码` ` 或 ``` 块状代码 ``` 支持多种语言高亮 无序列表 - 列表项 自动层级缩进 有序列表 + 列表项 自动编号 术语列表 / 术语: 定义描述 常用于名词解释 链接 https://google.com 自动识别或使用 #link 函数 引用 \u0026gt; 引用文本 用于长段引用 注释 // 单行 或 /* 多行 */ 不会显示在输出文件中 数学公式 (Math Mode) # 使用美元符号 $ 进入数学模式。\n行内公式: $a + b = c$ 块级公式: $ v = s / t $ （在 $ 符号内侧保留空格） 常用数学语法： # 上下标: x^2, y_i 分式: 1/2 或 fract(a, b) 根号: sqrt(x) 希腊字母: 直接输入名称，如 alpha, beta, phi, Delta 矩阵: mat(1, 2; 3, 4) （分号分隔行） 求和/积分: sum, integral, product 限制范围: sum_(i=0)^n x_i 函数与脚本 (Scripting Mode) # 在 Typst 中，所有以 # 开头的标识符都代表函数调用或代码逻辑。\n常用内置函数 # 图片: #image(\u0026quot;logo.png\u0026quot;, width: 40%) 表格: 1#table( 2 columns: (1fr, auto, 1fr), 3 [左], [中], [右], 4 [1], [2], [3], 5) 形状与间隔: #rect[], #circle[], #h(1cm) (水平间距), #v(2pt) (垂直间距) 换页: #pagebreak() 样式设置 (Set \u0026amp; Show Rules) # 这是 Typst 实现自动化排版的核心。\nSet 规则 (全局状态设置) # 用于修改元素的默认属性：\n1#set page(paper: \u0026#34;a4\u0026#34;, margin: 2cm, numbering: \u0026#34;1\u0026#34;) // 纸张、边距、页码 2#set text(font: \u0026#34;SimSun\u0026#34;, size: 12pt, lang: \u0026#34;zh\u0026#34;) // 字体、字号、语言 3#set heading(numbering: \u0026#34;1.1 \u0026#34;) // 标题自动编号 4#set par(justify: true, first-line-indent: 2em) // 段落两端对齐、首行缩进 Show 规则 (元素重定义) # 用于改变特定元素的表现方式（类似于 CSS）：\n1// 将所有一级标题设为红色 2#show heading.where(level: 1): set text(red) 3 4// 在每个表格前自动加个加粗的提示 5#show table: it =\u0026gt; [ 6 *数据表：* 7 #it 8] 变量、编程与逻辑 # Typst 是一门完整的编程语言。\n定义变量: #let name = \u0026quot;Typst\u0026quot; 定义函数: 1#let notice(body) = rect(fill: gray.lighten(80%))[ 2 *注意：* #body 3] 4#notice[这是一个自定义提醒框] 条件判断: #if 1 \u0026lt; 2 [Yes] else [No] 循环: #for i in range(3) [ #i ] 标签与引用 # 定义标签: 在元素后面紧跟 \u0026lt;label_name\u0026gt;。 引用标签: 使用 @label_name。 1= 核心介绍 \u0026lt;intro\u0026gt; 2如章节 @intro 所述... 3 4#figure( 5 image(\u0026#34;graph.png\u0026#34;), 6 caption: [实验结果], 7) \u0026lt;fig_result\u0026gt; 8见图 @fig_result 。 常用快捷键/对比 (vs LaTeX) # 需求 Typst LaTeX 字体颜色 #text(fill: blue)[文本] \\textcolor{blue}{文本} 环境包裹 [...] \\begin{...} ... \\end{...} 加粗 *text* \\textbf{text} 导入模块 #import \u0026quot;template.typ\u0026quot;: * \\usepackage{...} 个人使用经验 # 最近在完善毕设论文，亲自使用了这个模板，一边发现问题一边修改问题hhhhh,感觉效率非常高。同样也总结了一些工作的经验。\n流程图 # 任何的论文都一定一定会有流程图，不管说是方法的流程，还是模型的结构，都需要流程图来让表达更加具体，让读者更容易，引用一个著名的理论论文就是要讲好一个故事，衡量论文，不光要从学术的角度看，也许要关注他的表述，怎么让读者看懂。 对于typst的流程图，我在我本人的毕设里面采用了两种方案，一种是通过drawio(现在叫digrams)来绘制，并导出pdf后再导入论文中。 typst插入论文图片使用以下的语法\n1#figure( 2 image(\u0026#34;image_path\u0026#34;,width=80%), 3 caution:[图片的描述] 4)第二种方案是使用typst嵌入的流程图绘制方式，typst作为开源项目，虽然原生的功能可能存在缺乏现象，但是会有很多开源社区的贡献来弥补，流程图的绘制，就会用到cetz这个库，首先在typ文件开头引用cetz\n1#import \u0026#34;@preview/cetz:0.3.4\u0026#34;然后就可以通过函数调用的方式来绘制具体的流程图，下面可以看到，真的非常之函数。\u0026#x1f601;\n1#figure( 2 align(center)[ 3 #cetz.canvas({ 4 import cetz.draw: * 5 6 let box-stroke = (paint: rgb(\u0026#34;#3E4A61\u0026#34;), thickness: 0.9pt) 7 let box-fill = rgb(\u0026#34;#F5F7FA\u0026#34;) 8 let arrow-stroke = (paint: rgb(\u0026#34;#4B5563\u0026#34;), thickness: 0.9pt) 9 10 let x1 = 0 11 let x2 = 6.4 12 let ys = (8.4, 7.2, 6.0, 4.8, 3.6, 2.4, 1.2) 13 let labels = ( 14 [加载 FP32 权重], 15 [构建 RAFT-Stereo 网络], 16 [模型参数转换为 FP16], 17 [输入图像预处理并转换为 FP16], 18 [执行半精度前向推理], 19 [输出视差图], 20 [统计指标并与 FP32 基线对比], 21 ) 22 23 for i in range(0, 7) { 24 let y = ys.at(i) 25 rect((x1, y - 0.35), (x2, y + 0.35), radius: 0.08, fill: box-fill, stroke: box-stroke) 26 content(((x1 + x2) / 2, y), labels.at(i)) 27 if i \u0026lt; 6 { 28 line(((x1 + x2) / 2, y - 0.35), ((x1 + x2) / 2, ys.at(i + 1) + 0.35), mark: (end: \u0026#34;\u0026gt;\u0026#34;), stroke: arrow-stroke) 29 } 30 } 31 }) 32 ], 33 caption: [基于 FP16 的半精度推理流程图], 34)编译出来的效果如下： 专业绘图 # 同样的专业绘图也可以交给cetz，其实他的专业绘图这么强，我也是没想到的。这个双目摄像头成像示意图就是完全由Chatgpt 5.4生成的，没想到效果这么惊艳。 代码如下\n1#figure( 2 align(center)[ 3 #cetz.canvas({ 4 import cetz.draw: * 5 6 // 定义核心几何参数 7 let b = 5 // 基线长度 b 8 let f = 1.5 // 相机焦距 f 9 let Z = 6 // 目标点深度 Z 10 11 let Ol = (0, 0) // 左相机光心 12 let Or = (b, 0) // 右相机光心 13 let P = (2, Z) // 空间目标点 P(X, Y, Z) 14 15 // 绘制基线与光心 16 line((-1, 0), (b + 1, 0), stroke: (dash: \u0026#34;dashed\u0026#34;, paint: luma(150)), name: \u0026#34;baseline\u0026#34;) 17 circle(Ol, radius: 0.06, fill: black) 18 content((0, -0.4), [$O_L$]) 19 circle(Or, radius: 0.06, fill: black) 20 content((b, -0.4), [$O_R$]) 21 22 // 标注基线 b 23 line((0, -0.8), (b, -0.8), mark: (start: \u0026#34;\u0026gt;\u0026#34;, end: \u0026#34;\u0026gt;\u0026#34;), stroke: 0.8pt) 24 content((b / 2, -1.2), [$b$]) 25 26 // 绘制图像平面 (高度为 f) 27 line((-1.5, f), (1.5, f), stroke: 1.2pt) 28 line((b - 1.5, f), (b + 1.5, f), stroke: 1.2pt) 29 30 // 标注焦距 f 31 line((-2, 0), (-2, f), mark: (start: \u0026#34;\u0026gt;\u0026#34;, end: \u0026#34;\u0026gt;\u0026#34;), stroke: 0.8pt) 32 content((-2.4, f / 2), [$f$]) 33 34 // 绘制空间点 P 及其到基线的垂线 35 circle(P, radius: 0.06, fill: black) 36 content((P.at(0), P.at(1) + 0.4), [$P(X,Y,Z)$]) 37 line((P.at(0), 0), P, stroke: (dash: \u0026#34;dotted\u0026#34;, paint: luma(100))) 38 39 // 标注深度 Z 40 line((b + 2, 0), (b + 2, Z), mark: (start: \u0026#34;\u0026gt;\u0026#34;, end: \u0026#34;\u0026gt;\u0026#34;), stroke: 0.8pt) 41 content((b + 2.4, Z / 2), [$Z$]) 42 43 // 绘制光线 (P 到光心) 44 line(P, Ol, stroke: (paint: blue.darken(20%), thickness: 0.8pt)) 45 line(P, Or, stroke: (paint: blue.darken(20%), thickness: 0.8pt)) 46 47 // 计算投影点位置 (利用相似三角形严谨计算) 48 let xL_pos = P.at(0) * (f / Z) 49 let xR_pos = b + (P.at(0) - b) * (f / Z) 50 51 let pL = (xL_pos, f) 52 let pR = (xR_pos, f) 53 54 // 绘制并标注左侧投影点 x_L 55 circle(pL, radius: 0.05, fill: red) 56 content((xL_pos - 0.4, f + 0.3), text(fill: red)[$x_L$]) 57 58 // 绘制并标注右侧投影点 x_R 59 circle(pR, radius: 0.05, fill: red) 60 content((xR_pos + 0.4, f + 0.3), text(fill: red)[$x_R$]) 61 }) 62 ], 63 caption: [双目视觉立体测距原理示意图], 64)我将永远拥护Chatgpt和typst（如果可以的话），听说那些专业期刊会要求提供tex格式的文件，这不就炸了，不过本科毕设肯定不会要求的，我感觉我同学百分之九十五都不会使用latex来写毕业论文，大部分估计都是word系。\n同样对于柱状图，我们也可以直接使用cetz来绘制。 代码如下：\n1#figure( 2 align(center)[ 3 #cetz.canvas({ 4 import cetz.draw: * 5 6 let axis-stroke = (paint: rgb(\u0026#34;#4B5563\u0026#34;), thickness: 0.9pt) 7 let grid-stroke = (paint: luma(220), thickness: 0.5pt) 8 let fp32-fill = rgb(\u0026#34;#8FB7E8\u0026#34;) 9 let fp16-fill = rgb(\u0026#34;#F2A978\u0026#34;) 10 11 // 坐标轴与网格 12 line((1.2, 0.8), (1.2, 6.0), stroke: axis-stroke) 13 line((1.2, 0.8), (8.6, 0.8), stroke: axis-stroke) 14 line((1.2, 1.8), (8.6, 1.8), stroke: grid-stroke) 15 line((1.2, 2.8), (8.6, 2.8), stroke: grid-stroke) 16 line((1.2, 3.8), (8.6, 3.8), stroke: grid-stroke) 17 line((1.2, 4.8), (8.6, 4.8), stroke: grid-stroke) 18 line((1.2, 5.8), (8.6, 5.8), stroke: grid-stroke) 19 20 // 纵轴刻度 21 content((0.7, 0.8), [0]) 22 content((0.55, 1.8), [50]) 23 content((0.45, 2.8), [100]) 24 content((0.45, 3.8), [150]) 25 content((0.45, 4.8), [200]) 26 content((0.45, 5.8), [250]) 27 content((0.6, 6.35), [时间/ms]) 28 29 // 柱状图 30 rect((2.3, 0.8), (4.2, 5.0), fill: fp32-fill, stroke: none) 31 rect((5.4, 0.8), (7.3, 4.27), fill: fp16-fill, stroke: none) 32 33 // 数值与标签 34 content((3.25, 5.28), [209.80]) 35 content((6.35, 4.55), [173.59]) 36 content((3.25, 0.35), [FP32]) 37 content((6.35, 0.35), [FP16]) 38 }) 39 ], 40 caption: [FP32 与 FP16 速度对比柱状图], 41)效果如图所示 表格 # typst原生支持表格，通过使用table可以来创建表格。 代码如下：\n1#figure( 2 table( 3 columns: (22%, 28%, 50%), 4 stroke: none, 5 align: (x, y) =\u0026gt; ( 6 if y == 0 { center + horizon } 7 else if x \u0026lt;= 1 { center + horizon } 8 else { left + horizon } 9 ), 10 11 table.hline(y: 0, stroke: 1.5pt), 12 table.header([*指标类别*], [*统计指标*], [*说明*]), 13 table.hline(y: 1, stroke: 0.5pt), 14 15 [精度指标], [EPE、D1], [衡量预测视差与真实视差之间的误差，用于判断半精度转换是否影响匹配精度。], 16 table.hline(y: 2, stroke: 0.5pt), 17 18 [速度指标], [AvgTime、FPS], [衡量单张图像推理耗时和连续处理能力，用于评价推理效率。], 19 table.hline(y: 3, stroke: 0.5pt), 20 21 [资源指标], [Max CUDA Memory], [统计推理过程中的 GPU 显存峰值，用于分析显存占用变化。], 22 table.hline(y: 4, stroke: 0.5pt), 23 24 [存储指标], [Model Size], [统计模型权重文件大小，用于评价模型部署和分发成本。], 25 table.hline(y: 5, stroke: 1.5pt), 26 ), 27 caption: [FP16 轻量化实验评价指标说明], 28 kind: table 29) 引用文献 # 只要是论文，必然会用引用文献，我们每个人都是站在巨人肩上修修补补，所以typst必然需要有引用文献的功能。\u0026#x1f600; 在thesis.typ的同目录下会有ref.bib，在其中可以添加参考文献目录。然后再文章中可以通过@文献名来引用，注意，不光要创建这样的ref.bib文件，并按照指定格式输入，还需要在thesis.typ中显式的使用它，具体可以看以下：\n文献参考格式 # 大概可以按照这样的格式来写\n1@article{ref02_Hirschmuller2008SGM, //文章中引用就@这个名字 2 author = {Hirschmuller, Heiko}, 3 title = {Stereo Processing by Semi-Global Matching and Mutual Information}, 4 journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, 5 year = {2008}, 6 volume = {30}, 7 number = {2}, 8 pages = {328-341} 9} 10 11@inproceedings{ref03_Scharstein2014Middlebury, 12 author = {Scharstein, Daniel and Hirschmuller, Heiko and Kitajima, Yukihiro and Krathwohl, Greg and Ne{\\v{s}}i{\\\u0026#39;c}, Nera and Wang, Xi and Westling, Porter}, 13 title = {High-Resolution Stereo Datasets with Subpixel-Accurate Ground Truth}, 14 booktitle = {German Conference on Pattern Recognition (GCPR)}, 15 year = {2014} 16} 全局定义 # 1#let ( 2 functions 3) = documentclass( 4 5fonts: ( 6 font-settings 7), 8 info: ( 9 info.... 10 ), 11 bibliography: bibliography.with(\u0026#34;ref.bib\u0026#34;), 12)要在bibliography中改成自己的文献参考集的名字。\n文章整体引用 # 只在前面的全局定义中写完了还不够，还需要在文章主体中使用文献参考集。\n1#bilingual-bibliography(full: true)要把这一行放在文末。 之后就可以直接通过@来引用了。\n发发发 😠，学校毕业终稿不支持pdf提交，发发发，气死了，最后还要调格式。只有最迂腐最笨的学校才会有这样的规定。\n","date":"2026-04-17","externalUrl":null,"permalink":"/p/modern-swjtu-thesis%E5%BC%80%E5%8F%91/","section":"技术博客","summary":"最近正在准备写本科毕业设计论文，不想用微软的word写，因为感觉不够极客 😧 ，也不想使用LaTex，因为LaTex太笨重了，编译速度太慢了，在线服务overleaf又是收费的（帮黄学长报销这个来着，好像一个月要三百多 🙀） 在网上搜罗搜罗发现了typst，一个基于rust内核的开源的标记语言排版系统，速度非常快，功能我觉得的也足够强（公式什么的都能很好地显示），同时我在他的模板库也找到了其他大学的毕业论文模板（nju），于是基于这个模板，我便衍生做一个swjtu的版本，最后，感谢nju-lug。\n","title":"Modern Swjtu Thesis开发","type":"posts"},{"content":"","date":"2026-04-17","externalUrl":null,"permalink":"/categories/project/","section":"分类","summary":"","title":"Project","type":"categories"},{"content":"","date":"2026-04-17","externalUrl":null,"permalink":"/tags/template/","section":"Tags","summary":"","title":"Template","type":"tags"},{"content":"","date":"2026-04-17","externalUrl":null,"permalink":"/tags/typst/","section":"Tags","summary":"","title":"Typst","type":"tags"},{"content":"","date":"2026-04-14","externalUrl":null,"permalink":"/tags/agent/","section":"Tags","summary":"","title":"Agent","type":"tags"},{"content":"","date":"2026-04-14","externalUrl":null,"permalink":"/categories/experiment/","section":"分类","summary":"","title":"Experiment","type":"categories"},{"content":"最近刚刚入职了某小厂，作为ai实习生，也是开启了自己的牛马生涯。 公司的第一个任务就是做一个电商客服，我在网络上搜罗了一下可能比较成形的方案，最终决定选择使用fastgpt框架调用qwen api+千牛后台。\n介绍 # fastgpt是是一个ai agent搭建平台，提供了开箱即用的数据处理和模型调用能力，可以方便的本地化部署工作流。而且这个项目好像是中文项目，感觉ai agent领域很多都是中文（比如还有dify）。\n工作流介绍 # 我的智能客服工作流是在他在线方案的模板下，简单改了一下，模板可以通过这个网站访问。\n下面为流程图 系统配置 # 设置开场白，如：\n1您好！欢迎光临云米净水旗舰店！❤️ 2我是您的专属顾问。 3想要咨询一些什么问题呢 流程开始 # 用户输入问题string，会直接进入安抚程序。\n用户意图解析 # 通过问题分类将用户的问题string输入到qwen flash，可以对问题进行大致分类，比如分成产品问题售后类，其他类（打招呼，情绪宣泄）。对于不同的问题走不一样的后续流程。\n产品品类解析 # 同样还是通过调用qwen flash，来判断问题有关的产品是什么。方便调用对应的知识库来查询。\n知识库查询 # 知识库使用的embedding模型也是阿里旗下的text-embedding-v4(因为阿里有免费额度 😄) 💯，知识库检索的重排模型使用的是gte-rerank-v2 。\n查询融合 # 因为可能会走不同的知识库查询，为了方便下文中调用，通过这个查询融合模块就可以不用管走哪个数据库，住模型都使用相同的数据库变量。\n主模型 # 根据用户问题和知识库查询结果，输出客服回答。\n遇到的问题 # 一开始我虽然知道对于客服这种对回复效率有一定要求的agent，不能使用思考类模型，于是我一开始特地使用的就是带flash（🤗）的模型即qwen3.5-flash，但是还是不行还是会存在思考过程。导致输出非常地慢，会要一分多钟。后来选择了qwen-flash，就没有这个问题了，效果也还可以。\n我一开始就是白嫖的阿里的免费额度，阿里是每个模型都有独立的免费额度，我原本以为我会先把qwen-flash用完，但是我没想到的，最先用完的是embedding模型（好像据说每次知识库搭建和调用都会使用embedding模型），后来为了方便测试含泪😢爆了10块大洋，后续部署的话希望公司买点api吧。\n过了一段时间，我对原本的智能客服进行了迭代升级，因为我们有对问题要求有了更精细的划分，比如：售前，售后；净水类，厨卫类，于是进行了迭代，但是再次不做过多赘述，因为后面我的任务被分配为针对云米净水旗舰店去做这样的ai客服，下面让我继续聊我的工作进展\nQ:问题汇总 # failed to upload error # 据ai解释好像是因为脚本默认推荐的ip是192.18.0.1，这是一个docker内部虚拟的网桥地址，浏览器和minio没办法访问到，所以在开始设置时可以直接设置自己在局域网的ip,这样的话不太会出现上传不了的现象。 但是很明显，局域网的ip很有可能会变化，因为dhcp协议会自动分配ip地址，如果你可以访问到路由器管理员页面，可以在路由器里面设置静态ip，将ip和设备mac捆绑起来。 但是如果你没办法访问后台的话，可以每次开始工作前，去docker-compose.yml中重新设置一下， 通过以下命令得到ip地址\n1ip addr show设置成局域网ip。\n1STORAGE_EXTERNAL_ENDPOINT: http://192.168.2.190:9000 # 一个服务器和客户端均可访问到存储桶的地址，可以是固定的宿主机 IP 或者域名，注意不要填写成 127.0.0.1 或者 localhost 等本地回环地址(因为容器里无法使用)之后每次出现重新开始工作如果局域网ip\u0026#x1f587;\u0026#xfe0f;变了，就执行一下上面的更改，再重新通过当前的ip:3000来访问这个前端网页\u0026#x1f578;\u0026#xfe0f;。\n","date":"2026-04-14","externalUrl":null,"permalink":"/notes/fastgpt%E5%88%9D%E4%BD%93%E9%AA%8C1/","section":"知识笔记","summary":"最近刚刚入职了某小厂，作为ai实习生，也是开启了自己的牛马生涯。 公司的第一个任务就是做一个电商客服，我在网络上搜罗了一下可能比较成形的方案，最终决定选择使用fastgpt框架调用qwen api+千牛后台。\n","title":"Fastgpt初体验1","type":"notes"},{"content":"","date":"2026-04-04","externalUrl":null,"permalink":"/tags/rust/","section":"Tags","summary":"","title":"Rust","type":"tags"},{"content":" Trait # trait（特征）是一种定义共享行为的机制，可以理解成其他语言中的接口，相当于是不管你底层是什么数据类型，只要定义了这个trait，就一定要实现这个trait的功能。\n定义和实现 # trait本质上是一组方法签名的集合，你可以定义一个trait并为不同的结构体去实现这个trait，代码实例如下\n1// 1. 定义一个名为 `MakeSound` 的 Trait，规定了必须有一个 `sound` 方法 2pub trait MakeSound { 3 fn sound(\u0026amp;self) -\u0026gt; String; 4} 5 6// 2. 定义两个完全不同的结构体 7struct Dog; 8struct Cat; 9 10// 3. 为 Dog 实现 `MakeSound` 契约 11impl MakeSound for Dog { 12 fn sound(\u0026amp;self) -\u0026gt; String { 13 String::from(\u0026#34;汪汪！\u0026#34;) 14 } 15} 16 17// 4. 为 Cat 实现 `MakeSound` 契约 18impl MakeSound for Cat { 19 fn sound(\u0026amp;self) -\u0026gt; String { 20 String::from(\u0026#34;喵喵！\u0026#34;) 21 } 22} 主要作用 # trait主要的有下面几个特点\n多态：允许编写处理多种类型的通用代码，你可以写一个函数，不关心她是Dog还是Cat，只关心传入的类型能否make_sound。 1// 这个函数接收任何实现了 MakeSound 的类型 2fn play_sound(animal: \u0026amp;impl MakeSound) { 3 println!(\u0026#34;听到声音: {}\u0026#34;, animal.sound()); 4} 泛型约束：trait可以来限制泛型能够接受的类型。例如\u0026lt;T:MakeSound\u0026gt;表示T可以是任何类型，但是必须实现了MakeSound这个trait。 代码复用：trait中的方法可以有默认的实现逻辑，如果某个类型实现了trait但是没有重写方法，则会自动获得默认行为。 rust内置的trait # rust极其依赖trait，这也是rust设计优雅的原因，有很多理所当然的行为，实际上都是trait：\nDebug和Display：可以使用println(\u0026quot;{:?}\u0026quot;,x)来打印变量。 Clone和Copy：定义了数据的复制 Add和Sub：定义了+和-如何对非基础类型进行数学运算 rust的trait还符合开闭原则，即倘若要新增一个动物，无需重写playsound这个函数，而是直接新建一个动物结构体，并且为他impl MakeSound就可以了。 还体现了职责分离这一特点，MakeSound只负责发出声音，动物的逻辑只在动物的部分内，不同的模块就被安全的隔开了。 dyn # ","date":"2026-04-04","externalUrl":null,"permalink":"/notes/rust%E5%AD%A6%E4%B9%A001-%E6%89%80%E6%9C%89%E6%9D%83/","section":"知识笔记","summary":"Trait # trait（特征）是一种定义共享行为的机制，可以理解成其他语言中的接口，相当于是不管你底层是什么数据类型，只要定义了这个trait，就一定要实现这个trait的功能。\n","title":"Rust学习01-所有权","type":"notes"},{"content":"","date":"2026-03-31","externalUrl":null,"permalink":"/tags/blog/","section":"Tags","summary":"","title":"Blog","type":"tags"},{"content":"","date":"2026-03-31","externalUrl":null,"permalink":"/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"2026-03-31","externalUrl":null,"permalink":"/tags/self-host/","section":"Tags","summary":"","title":"Self-Host","type":"tags"},{"content":"","date":"2026-03-31","externalUrl":null,"permalink":"/tags/ssl/","section":"Tags","summary":"","title":"SSL","type":"tags"},{"content":"最近正在因为换了浏览器，进行过一次密码迁移，在迁移的过程中总感觉有种隐忧，就是密码泄露或者丢失的风险 其实密码泄露给这些大型的公司比如Microsoft/Google，其实对我没影响，但是如果片丢失了，就影响大了，因为我有很多的网络站点都是使用浏览器生成的强密码，此前很多密码管理工具也出现过数据丢失的问题。 所以我想着自己搭建属于自己的服务来实现，更安全（但不一定更可靠）的密码服务。\n调研 # 我简单调查了市面上所有的密码管理器，主要分为两部分：\na、云服务：除了依赖浏览器厂商，还有一些专业的密码服务厂商，比如被广泛使用的1password和以隐私保护著称的proton pass，但是这两个的服务都不是免费的，而且都不便宜，国内的连接也不够稳定。 b、自搭建服务：使用大名鼎鼎的bitwarden或者keepassxc，后者很安全，因为数据文件只能保存在本地，但问题也就是他没有任何的云服务，非常不方便。 最终我决定使用vaultwarden，一个基于bitwarden的rust重写版（rust信徒狂喜），使用我之前的买的一个火山云的服务器2g2核，足够运行。当时这个服务器还是用来跑openclaw的，后来没弄成，就闲置下来了。\n部署 # 部署要求 # 云服务器：由于rust底层，导致占用很低，2gb2核绝对够用 域名：需要一个域名，因为需要ios自动填充和chrome插件都需要HTTPS环境，所以需要把域名解析到我的个人服务器上，并且需要SSL证书。 环境要求：服务器最好有docker环境 部署过程 # 配置docker # 这是第一步，对于国内来说也是最难的一步，因为服务器不同于个人网络，不可以部署vpn服务，所以要配置要准备好可以连接的docker是最麻烦的，首先是docker安装，可以在部署服务器的时候，可以选择自带并且安装好docker的环境。对于不同的服务器厂商，可以直接搜各自指定的文档来安装docker。 安装docker，通常不会出现问题，问题主要出现在拉取镜像上，网上对于这方面的解决措施纷繁复杂，什么配置镜像源，什么本地pull再传到服务器上，我这里之给出一种解决我的问题的方法\n1ms：一毫秒，是一个国内可以访问的docker代理网站 1docker pull docker.1ms.run/vaultwarden/server:latest 2docker pull docker.1ms.run/library/caddy:2此处下载了两个镜像，一个是vaultwarden本地，另一个是caddy，用来反向代理的\n安装环境 # 首先创建文件夹\n1mkdir -p /home/somnus/vaultwarden 2cd /home/somnus/vaultwarden接着就是创建Caddyfile，他是用来全自动申请和续签Let\u0026rsquo;s Encrypt 的 HTTPS 证书，完全不需要手动配置。\n1nano Caddyfile并输入以下内容\n1pwd.yourdomain.com { #此处替代为自己的域名 2 reverse_proxy vaultwarden:80 3}并保存退出\n创建docker-compose.yaml # 创建该yaml文件\n1nano docker-compose.yaml并且输入以下内容\n1version: \u0026#39;3\u0026#39; 2 3services: 4 vaultwarden: 5 image: vaultwarden/server:latest 6 container_name: vaultwarden 7 restart: always 8 environment: 9 - WEBSOCKET_ENABLED=true 10 - SIGNUPS_ALLOWED=true # 第一次启动设为 true，注册完后改为 false 11 volumes: 12 - ./vw-data:/data 13 14 caddy: 15 image: caddy:2 16 container_name: caddy 17 restart: always 18 ports: 19 - 80:80 # 必须映射 80 和 443 端口 20 - 443:443 21 volumes: 22 - ./Caddyfile:/etc/caddy/Caddyfile:ro 23 - ./caddy-data:/data 24 - ./caddy-config:/config 25 depends_on: 26 - vaultwarden保存并退出，执行以下命令\n1sudo docker compose up -d此时如果一切正常，你在访问自己的域名的时候就能进入vaultwarden的登陆界面了。\n备案 # 如果你选择的是国内的运营商的服务器，那么不可避免的你都需要进行备案，可以直接按照对应公司的备案流程来。 备案时间真的很长，至少需要一周左右。所以现在都再等待备案通过。\n过了大概三天，工信部的备案就通过了，再过不到24hour，就可以直接访问这个网站了。 网站页面如下： 点击下方的注册，创建账号，输入邮箱和主密码，注意注意注意，这个主密码一定要记住，一定要存在一个你记得的地方。因为主密码忘记之后无法恢复。 注册完账号之后就可以登陆并导入浏览器的密码本。\n","date":"2026-03-31","externalUrl":null,"permalink":"/p/vaultwarden%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/","section":"技术博客","summary":"最近正在因为换了浏览器，进行过一次密码迁移，在迁移的过程中总感觉有种隐忧，就是密码泄露或者丢失的风险 其实密码泄露给这些大型的公司比如Microsoft/Google，其实对我没影响，但是如果片丢失了，就影响大了，因为我有很多的网络站点都是使用浏览器生成的强密码，此前很多密码管理工具也出现过数据丢失的问题。 所以我想着自己搭建属于自己的服务来实现，更安全（但不一定更可靠）的密码服务。\n","title":"Vaultwarden使用教程","type":"posts"},{"content":"","date":"2026-03-31","externalUrl":null,"permalink":"/tags/vps/","section":"Tags","summary":"","title":"VPS","type":"tags"},{"content":" 一、轻量化部署方向工作总结 # 1、研究动机 # 在前期实验中，基于 RAFT-Stereo 的 refinement head、边缘感知损失以及 partial unfreeze 等改进方法，并未在 Middlebury 数据集上取得稳定、显著的精度提升，说明原始 raftstereo-middlebury 模型本身已经具有较强性能，小规模真实域数据下难以通过小幅结构改动进一步提升整体指标。\n因此，后续工作将研究重点由“继续提升精度”转向“在尽量保持精度的前提下降低模型部署开销”，即探索 RAFT-Stereo 在边缘设备上的轻量化部署方案。\n2、轻量化研究思路 # 本阶段主要围绕以下两个方向展开：\n(1)、官方轻量模型对比：realtime 版本 # 首先，选择官方提供的 raftstereo-realtime.pth 作为轻量化基线模型，与高精度的 raftstereo-middlebury.pth 进行对比。该模型通过减少网络规模、降低迭代次数、共享部分骨干结构等方式提升实时性，目标是在更低资源消耗下完成双目匹配任务。\n这一实验的目的在于验证：直接采用官方轻量模型，是否能够在保证可接受精度的前提下实现部署端优化。\n(2)、半精度部署：FP16 # 在发现 realtime 模型精度下降较明显后，进一步尝试 FP16 半精度部署方案。该方案不改变原始 RAFT-Stereo 网络结构，也不重新训练模型，而是直接将高精度的 raftstereo-middlebury.pth 转换为半精度权重模型，并在推理与评测阶段采用 FP16 进行部署测试。\n这一方案的核心思想是：\n保留原始高精度模型结构； 避免重新训练带来的额外成本； 通过降低数值精度减少模型文件大小、显存占用和推理时间； 在尽量保持原始精度的前提下，实现更适合边缘设备的部署形式。 3、实验设置 # (1)、模型与环境 # 项目 设置 高精度基线模型 RAFT-Stereo (raftstereo-middlebury.pth) 轻量化对照模型 RAFT-Stereo Realtime (raftstereo-realtime.pth) 半精度模型 RAFT-Stereo FP16 (raftstereo-middlebury-fp16.pth) 推理设备 GPU：NVIDIA 4090 correlation reg (2)、对比方案 # 本阶段主要设置了三组对比：\nBaseline FP32：原始 raftstereo-middlebury.pth Realtime：官方轻量化实时模型 raftstereo-realtime.pth FP16：由 raftstereo-middlebury.pth 转换得到的半精度模型 raftstereo-middlebury-fp16.pth (3)、评价维度 # 为了从部署角度评价模型轻量化效果，本阶段不仅关注匹配精度，还额外统计了以下指标：\nEPE：平均像素误差 D1：离群点比例 模型大小：模型文件存储开销 Average Inference Time：平均推理时间 FPS：每秒处理帧数 Max CUDA Memory Allocated：推理阶段显存占用峰值 4、实验结果 # (1)、官方 realtime 模型与高精度模型对比 # 模型 参数量 EPE D1 RAFT-Stereo Middlebury 11.14M 2.3758 12.0526 RAFT-Stereo Realtime 9.89M 11.1557 28.5460 从结果可以看出，官方 realtime 模型参数量相较高精度 Middlebury 模型有所减少，但在 Middlebury2014 数据集上的精度下降非常明显：\nEPE 由 2.3758 上升到 11.1557 D1 由 12.0526 上升到 28.5460 这说明：直接采用官方轻量模型虽然能够降低模型规模，但会带来较大的精度损失，不适合作为当前任务的最终部署方案。\n(2)、FP16 半精度部署结果 # 模型 EPE D1 平均推理时间 FPS 最大显存占用 模型大小 Baseline FP32 2.3758 12.0526 209.80 ms 4.77 844.91 MB 43 MB FP16 2.3535 12.0593 173.59 ms 5.76 662.34 MB 22 MB 进一步计算可得：\n模型大小：43 MB → 22 MB，下降约 48.8% 显存占用：844.91 MB → 662.34 MB，下降约 21.6% 平均推理时间：209.80 ms → 173.59 ms，缩短约 17.3% FPS：4.77 → 5.76，提升约 20.8% 而在精度方面：\nEPE：2.3758 → 2.3535，基本保持一致 D1：12.0526 → 12.0593，几乎不变 这说明：将高精度 Middlebury 模型直接转换为 FP16 半精度模型后，模型精度基本保持稳定，同时明显降低了模型存储、显存占用和推理时间。\n原图 baseline fp16 5、结果分析 # 通过本阶段实验，可以得到如下分析：\na、官方 realtime 轻量模型存在明显精度代价 # 虽然 realtime 模型在参数量上比高精度 Middlebury 模型更小，但在 Middlebury2014 数据集上的 EPE 和 D1 均大幅恶化，说明这种结构级轻量化方式是以显著牺牲匹配精度为代价实现的。\nb、FP16 半精度部署是一种更稳妥的轻量化方式 # 与直接更换轻量模型不同，FP16 方案不改变原始网络结构，因此保留了高精度模型已经学习到的匹配能力。实验表明，在几乎不损失精度的情况下，FP16 能够显著减小模型文件体积，并降低显存和时间开销。\nc、对于当前任务，部署优化比结构替换更合适 # 结合前面对 refinement 系列方法和 realtime 模型的实验可以看出，对于 Middlebury 这种偏高精度需求的双目匹配任务，直接替换为更小的轻量结构往往会带来较大精度损失；相比之下，在保持主模型结构不变的基础上做半精度部署，更适合作为当前阶段的轻量化方案。\n6、实验结论 # 通过本次轻量化部署实验，可以得到以下结论：\n官方 raftstereo-realtime 模型虽然在参数规模上更小，但在 Middlebury2014 数据集上的精度下降明显，难以满足高精度双目匹配任务需求； 基于 raftstereo-middlebury.pth 的 FP16 半精度部署方案，在不改变原始模型结构、也不重新训练的前提下，实现了模型体积、显存占用和推理时间的有效下降； FP16 模型在 EPE 和 D1 指标上与原始 FP32 模型基本保持一致，说明其能够在较好保留模型性能的同时降低部署开销； 相较于直接采用官方轻量化结构，FP16 半精度部署是一种更适合当前任务场景的轻量化方法； 该方法工程实现成本较低，部署路径清晰，具有进一步面向边缘设备应用的可行性。 7、后续规划 # 后续可以继续围绕以下方向展开：\n在 FP16 部署基础上，进一步补充不同输入分辨率下的推理速度与显存测试； 尝试在 Jetson 等边缘硬件平台上验证实际部署效果； 进一步探索剪枝、蒸馏等轻量化方法，与 FP16 方案形成对比； 在保持精度的前提下，研究更适合嵌入式或低功耗场景的双目匹配部署策略。 ","date":"2026-03-30","externalUrl":null,"permalink":"/p/secret-111-share/","section":"技术博客","summary":"一、轻量化部署方向工作总结 # 1、研究动机 # 在前期实验中，基于 RAFT-Stereo 的 refinement head、边缘感知损失以及 partial unfreeze 等改进方法，并未在 Middlebury 数据集上取得稳定、显著的精度提升，说明原始 raftstereo-middlebury 模型本身已经具有较强性能，小规模真实域数据下难以通过小幅结构改动进一步提升整体指标。\n","title":"260328","type":"posts"},{"content":"","date":"2026-03-29","externalUrl":null,"permalink":"/tags/code/","section":"Tags","summary":"","title":"Code","type":"tags"},{"content":" p002 # 题目 # Problem 2: Even Fibonacci numbers\n题目链接\nEach new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with $1$ and $2$, the first $10$ terms will be: $$1, 2, 3, 5, 8, 13, 21, 34, 55, 89, \\dots$$\nBy considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.\n这道题目的要求是算出Fibonacci数列的前4000000个数字中的偶数之和。\n解答 # 这题如果直接做，可以直接根据Fibonacci数列的规律，直接while循环判断。\n$$ F(n) = F(n-1)+F(n-2) $$代码如下\n1fn solve2() -\u0026gt; u64 { 2 let mut a = 1; 3 let mut b = 2; 4 let mut sum = 0; 5 while a \u0026lt;= 4_000_000 { 6 if a % 2 == 0 { 7 sum += a; 8 } 9 let next = a + b; 10 a = b; 11 b = next; 12 } 13 sum 14}很明显，这样是能算到最终结果的，最终的结果就是4613732，但这个太暴力很明显不值得我特地写一篇博客。\n此时，我们好好回顾一下这个问题，要求一个fibonacci数列的所有偶数，我们在写这个数列的时候会发现数列中的偶数是隔着两个奇数就有一个偶数，如果把所有偶数剔出来，会发现满足一下的规律。\n$$ F(n) = 4*F(n-1) + F(n-2) $$自此可以看出来时间复杂度从O(n)-\u0026gt;O(n/3)。 rust代码如下\n1fn solve1() -\u0026gt; u64 { 2 let mut a = 2; 3 let mut b = 8; 4 let mut sum = 0; 5 6 while a \u0026lt;= 4_000_000 { 7 sum += a; 8 let next = 4 * b + a; 9 a = b; 10 b = next; 11 } 12 sum 13}计算时间上面呢也就减少了20ns，但是这样的降低时间复杂度的操作还是很有意义的。从中我们也可以得到启发，当程序无法进行优化时，可以从数学的角度入手。下面是运行时间对比图片(我把测试增加了)。 p004 # 题目 # Problem 4: Largest Palindrome Product\n题目链接 题目描述:\nA palindromic number reads the same both ways. The largest palindrome made from the product of two $2$-digit numbers is $9009 = 91 \\times 99$.\n问题: Find the largest palindrome made from the product of two $3$-digit numbers.\n解答a # 同样，这题可以直接设定i和j代表两个数。直接开始循环，然后通过一个函数判断乘积是否是回文数。代码如下：\n1fn is_palindrome(n: u64) -\u0026gt; bool { 2 let s = n.to_string(); 3 s.chars().eq(s.chars().rev()) 4} 5fn baolisolve() -\u0026gt; u64 { 6 let mut max_palindrome = 0; 7 for i in 100..999 { 8 for j in 100..999 { 9 let x = i * j; 10 if is_palindrome(x) \u0026amp;\u0026amp; x \u0026gt;= max_palindrome { 11 max_palindrome = x; 12 } 13 } 14 } 15 max_palindrome 16}最后得到的计算时间也是相当可观了（计算时间很长） 解答b # 此时可以观察到，要求出最大的回文数，往往两个数字都需要大概900多的样子，我们可以直接从后向前循环，这样的话时间就能减少很多。 解答c # 首先引入一个结论，任何一个偶数位数的回文数都可以被11整除。在本题目中，要求最大的六位回文数，则该回文数必然有一个因数也可以被11整除。于是便可以减少部分循环次数，进一步降低时间消耗。 代码如下\n1fn mathsolve() -\u0026gt; u64 { 2 let mut max_palindrome = 0; 3 for i in (100..999).rev() { 4 let start = if i % 11 == 0 { 999 } else { 990 }; 5 let step = if i % 11 == 0 { 1 } else { 11 }; 6 let mut j = start; 7 while j \u0026gt;= 100 { 8 let n = i * j; 9 if n \u0026lt;= max_palindrome { 10 break; 11 } 12 if is_palindrome(n) { 13 max_palindrome = n; 14 } 15 j -= step; 16 } 17 } 18 max_palindrome 19}最后可以看到消耗时间被降低到了微秒级别 简单证明一下上面这个结论。 设一个 6 位回文数写成：\n\\[ N = \\overline{abccba} \\]其中 \\(a,b,c\\) 都是数字，且 \\(a \\neq 0\\)。\n把它按十进制展开：\n\\[ N = 100000a + 10000b + 1000c + 100c + 10b + a \\]整理同类项可得：\n\\[ N = 100001a + 10010b + 1100c \\]接下来把每一项提取出 11：\n\\[ 100001 = 11 \\times 9091 \\]\\[ 10010 = 11 \\times 910 \\]\\[ 1100 = 11 \\times 100 \\]所以：\n\\[ N = 11(9091a + 910b + 100c) \\]因此，\\(N\\) 一定能被 11 整除。\n任意 6 位回文数都可以写成 11 的倍数，因此：\n\\[ \\boxed{\\text{任意 6 位回文数一定能被 11 整除}} \\] 数学博大精深～～！\np005 # 题目 # Problem 5: Smallest Multiple\n题目链接\n题目描述:\n$2520$ is the smallest number that can be divided by each of the numbers from $1$ to $10$ without any remainder.\n问题: What is the smallest positive number that is evenly divisibledivisible with no remainder by all of the numbers from $1$ to $20$?\n解答 # 这题需要求出1-20所有数字的lcm(最小公倍数)。\n$$ lcm(a,b) = \\frac{a * b}{gcd(a , b)} $$代码如下\n1fn gcd(mut a: u64, mut b: u64) -\u0026gt; u64 { 2 while b != 0 { 3 let temp = b; 4 b = a % b; 5 a = temp; 6 } 7 a 8} 9 10fn lcm(a: u64, b: u64) -\u0026gt; u64 { 11 a / gcd(a, b) * b 12} 13 14fn solve() -\u0026gt; u64 { 15 (1..20).reduce(|acc, c| lcm(acc, c)).unwrap() 16} ","date":"2026-03-29","externalUrl":null,"permalink":"/notes/eulerproj01/","section":"知识笔记","summary":"p002 # 题目 # Problem 2: Even Fibonacci numbers\n","title":"Eulerproj01","type":"notes"},{"content":"","date":"2026-03-29","externalUrl":null,"permalink":"/categories/problem-solving/","section":"分类","summary":"","title":"Problem-Solving","type":"categories"},{"content":" 前情提要 # 我上一个训练日志中，尝试对RAFT-Stereo模型进行优化，通过添加refinement层和边缘损失感知，然后训练完的模型的EPE和D1几乎没有产生变化。因为这个层结构对整个模型来说都没什么影响。接着我在改完的这个模型后，对模型进行了partial unfreezement，然后在此基础上对middlebury数据集进行训练。最后得到的结果EPE和D1反而变差了，这个大概率是因为我本地的数据集太小，在此基础上进行训练会很容易导致过拟合的现象。自此，我便将研究重心转移到模型轻量化方面来。\n模型设计 # 首先，我先去官方库上找到了不同版本模型的下载链接。我原本一直都是使用他的middlebury版本，因为我本地的数据集也是middelbury，得到的效果也很好，然后我注意到除了middlebury，以外还有两个以数据集命名的预训练模型eth3d和sceneflow。还有一个模型就是raftstereo-realtime.pt，我后来调查得到，这个模型就是官方训练出来的轻量化版本，然，我就想着先拿这个模型测试一下。 除此以外，我还想了通过转换精度来实现轻量化，具体就是不改变模型原始网络结构，也不用重新训练模型，将原本的Float32转换成Float16,这样便可以大幅度降低模型的大小和显存占用，对于低显存的边缘设备，能提升帧率和处理速度。以下为处理代码，处理逻辑实际上value.half()这一句。\n1def convert_to_fp16(input_path, output_path): 2 print(f\u0026#34;Reading original checkpoint from: {input_path}\u0026#34;) 3 state_dict = torch.load(input_path, map_location=\u0026#39;cpu\u0026#39;) 4 new_state_dict = {} 5 for key, value in state_dict.items(): 6 if isinstance(value, torch.Tensor) and value.is_floating_point(): 7 new_state_dict[key] = value.half() # Convert to float16 8 else: 9 new_state_dict[key] = value # Keep non-floating-point parameters unchanged 10 print(f\u0026#34;Saving FP16 checkpoint to: {output_path}\u0026#34;) 11 torch.save(new_state_dict, output_path) 12 print(\u0026#34;Conversion completed successfully!\u0026#34;)这一方案的核心思想就是：\n保留原始高精度模型结构。 避免重新训练带来的额外成本。 训练结果 # 官方 realtime 模型与高精度模型对比 # 模型 参数量 EPE D1 RAFT-Stereo Middlebury 11.14M 2.3758 12.0526 RAFT-Stereo Realtime 9.89M 11.1557 28.5460 从结果可以看出，官方 realtime 模型参数量相较高精度 Middlebury 模型有所减少，但在 Middlebury2014 数据集上的精度下降非常明显：\nEPE 由 2.3758 上升到 11.1557 D1 由 12.0526 上升到 28.5460 这说明：直接采用官方轻量模型虽然能够降低模型规模，但会带来较大的精度损失，不适合作为当前任务的最终部署方案。\nFP16 半精度部署结果 # 模型 EPE D1 平均推理时间 FPS 最大显存占用 模型大小 Baseline FP32 2.3758 12.0526 209.80 ms 4.77 844.91 MB 43 MB FP16 2.3535 12.0593 173.59 ms 5.76 662.34 MB 22 MB 进一步计算可得：\n模型大小：43 MB → 22 MB，下降约 48.8% 显存占用：844.91 MB → 662.34 MB，下降约 21.6% 平均推理时间：209.80 ms → 173.59 ms，缩短约 17.3% FPS：4.77 → 5.76，提升约 20.8% 而在精度方面：\nEPE：2.3758 → 2.3535，基本保持一致 D1：12.0526 → 12.0593，几乎不变 这说明：将高精度 Middlebury 模型直接转换为 FP16 半精度模型后，模型精度基本保持稳定，同时明显降低了模型存储、显存占用和推理时间。\n小结 # 虽然我做出的改进非常小，但是得到的效果我觉得还是可以的，应该是足够支撑去作为本科毕业设计的成果的，但不知道胡老师会怎么看，希望能美美通关。\n","date":"2026-03-28","externalUrl":null,"permalink":"/p/raft%E8%AE%AD%E7%BB%83%E6%97%A5%E5%BF%972/","section":"技术博客","summary":"前情提要 # 我上一个训练日志中，尝试对RAFT-Stereo模型进行优化，通过添加refinement层和边缘损失感知，然后训练完的模型的EPE和D1几乎没有产生变化。因为这个层结构对整个模型来说都没什么影响。接着我在改完的这个模型后，对模型进行了partial unfreezement，然后在此基础上对middlebury数据集进行训练。最后得到的结果EPE和D1反而变差了，这个大概率是因为我本地的数据集太小，在此基础上进行训练会很容易导致过拟合的现象。自此，我便将研究重心转移到模型轻量化方面来。\n","title":"Raft训练日志2","type":"posts"},{"content":"最近做一些模型训练的项目，每次在训练的时候，长长的后续参数都让人很头大（每次都要问a：怎么让这个项目跑起来），于是我想是否可以弄一个项目，方便的设置参数，便有了这个项目。\n简单介绍 # 首先，为了保证模型训练的时候不能产生太多的内存和性能消耗，所以这个项目使用了rust来编写，实测这个项目的后台占用大概在20MB左右，几乎不会对模型训练产生影响。 其次，这个项目为了方便在终端运行，所以没有选用带GUI的前端，而是直接使用rust的终端显示库，ratatui，实际体验下来，这个库还是非常好用的，无论是api调用的方便性，还是便捷内存占用都是十分出色，非常适合我这个项目。\ninstall # 这个工具我已经上传crate.io，所以可以直接通过cargo install（没有安装rust环境的可以去装了:LOL ）\n1cargo install ml-launcher 使用 # 下载到本地后会自动安装到bin目录，可以直接在终端中调用。\n1ml-launcher之后就可以打开这样的界面 按下p可以编辑想要识别python 参数的位置，按下c可以设置config.json的位置（这个一般可以通过进入程序后save config获取到） 随意选择一个进入方式，便进入了这样的界面 首先，第一个table，Parameters：就是主界面，用来对每个参数（可以选择部分参数）设置对应的值，同时右边也可以看见该参数需要的类型和描述。下方的一排是在当前table可以使用的快捷键。 其次，第二个table，filter：可以通过选择某个参数按t，来改变是否需要手动设置值（因为在大部分情况下，很多参数是不需要手动输入的，直接使用默认值就行）左边的Filter可以进行滚动显示。 最后，第三个table，actions：主要有下面这些可以执行的动作（当前版本直接run code好像是有问题的，而且不能选择conda环境或者uv环境中的python，所以建议复制指令使用）。 代码结构讲解 # 当前版本是\u0026quot;0.1.0\u0026quot;，所以后续如果有改动，该逻辑可能不准\nmodeselector # 首先，刚进入程序会进入到模式选择，ModelSelector这个结构体是由以下元素组成的\n1pub struct ModeSelector { 2 // 主菜单状态 3 selected: usize, //作为选择的标志位。 4 // 路径输入 5 script_path: String, //输入的py文件地址，默认为当前目录下 6 config_path: String, 7 editing_script: bool, //设置一个bool值，方便表明该参数处于修改状态，会有不一样的颜色显示 8 editing_config: bool, 9 // 错误信息 10 error_msg: String, 11 // 退出标志 12 should_quit: bool, 13 // 继承配置对话框 14 show_inherit_dialog: bool, 15 inherit_selected: usize, 16 inherit_config_path: String, 17 editing_inherit_path: bool, 18 // 合并结果展示 19 show_merge_result: bool, 20 pending_merge_result: Option\u0026lt;MergeResult\u0026gt;, 21 pending_new_config: Option\u0026lt;TrainConfig\u0026gt;, 22}此处特地增加了一个should_quit的标志位，因为在没有这个标志位的时候，可能会因为两种不同的退出方式而产生冲突的bug。 ratatui设计的程序主要还有一个逻辑就是需要handle不同界面上的按键，分别有handle_main_menu_key，handle_inherit_dialog_key，handle_merge_result_key，handle_editing_script_key，handle_editing_config_key，handle_editing_inherit_path_key，分别对应不同的界面。 这个是第一部分的流程图。 主程序 # 如上面所介绍，主要分成三个table，其中，比较值得一说的是，主要有四个输入模式，\n1#[derive(Default, Clone, PartialEq)] 2pub enum InputMode { 3 #[default] 4 Normal, 5 Editing, 6 SaveDialog, 7 LoadDialog, 8}对于每个输入模式也有各自handle input的逻辑。每个handle input逻辑都需要处理不同按键和不同选择下的enter键。 每个参数都会有一个usedefault的布尔值，如果为ture，则不会再parameter中显示出来，反之则会显示，并且可以编辑对应的值。\n1 let active_params: Vec\u0026lt;(usize, \u0026amp;ParamField)\u0026gt; = self 2 .config 3 .params 4 .iter() 5 .enumerate() 6 .filter(|(_, p)| !p.use_default) 7 .collect();原本因为一个程序文件的总参数个数太多了，导致正常的终端的filter table根本没办法全部显示完，所以在这里改用了ListState来处理滚动显示逻辑。\n1let mut state = ListState::default(); 2 state.select(Some(self.selected_param)); 小结 # 哎哎哎哎，其实还是有挺多话之的说的，但是不太想写了，我最近再做另一个todolist的app，希望那个能纯手搓出来，而不要用vide coding，hhhhhh，加油吧～～～。\n","date":"2026-03-26","externalUrl":null,"permalink":"/p/ml-launcher%E5%BC%80%E5%8F%91/","section":"技术博客","summary":"最近做一些模型训练的项目，每次在训练的时候，长长的后续参数都让人很头大（每次都要问a：怎么让这个项目跑起来），于是我想是否可以弄一个项目，方便的设置参数，便有了这个项目。\n","title":"Ml Launcher开发","type":"posts"},{"content":"","date":"2026-03-26","externalUrl":null,"permalink":"/tags/readme/","section":"Tags","summary":"","title":"Readme","type":"tags"},{"content":"","date":"2026-03-26","externalUrl":null,"permalink":"/tags/tool/","section":"Tags","summary":"","title":"Tool","type":"tags"},{"content":"为什么用tmux：首先，因为我最近换了一个终端模拟器alacritty，这个模拟器不支持原生的分屏，需要通过tmux辅助。别问为什么非要用alacritty而不是自带分屏的ghostty，因为一个是rust一个是zig。 另外，我在使用服务器训练raft视觉模型的时候，偶尔因为网络断开连接，导致远程ssh关闭，自动的结束了训练，虽然我知道了可以使用nohup 在\u0026gt;输出到log文件中，但是还是觉得如果可以用tmux这种会更方便。\ntmux简介 # 为了解决上面提到的很常见的问题（关闭终端窗口\u0026amp;断开连接会导致任务（会话）终止），tmux的任务就是把session和窗口解除了绑定。 因此，tmux有三层结构，这样既解决了上面的问题，也推出了方便的分屏功能。\n1session（会话） 2 └── window（窗口） 3 └── pane（面板/分屏） 上面这个例子中就是在seesion：s1中的window：0。\ntmux安装 # 安装本体 # 1#Ubuntu \u0026amp; Debian 2sudo apt install tmux 3#CentOS \u0026amp; Fedora 4sudo yum install tmux 5# Mac 6brew install tmux 安装tpm（tmux插件管理工具） # 1git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm 配置conf文件 # 1nano ~/.tmux.conf 写入配置 # 1# ========================= 2# 基础配置 3# ========================= 4set -g prefix C-a 5unbind C-b 6bind C-a send-prefix 7 8set -g mouse on 9 10# ========================= 11# 插件管理 12# ========================= 13set -g @plugin \u0026#39;tmux-plugins/tpm\u0026#39; 14 15# Catppuccin主题 16set -g @plugin \u0026#39;catppuccin/tmux\u0026#39; 17 18# 可选：增强体验插件 19set -g @plugin \u0026#39;tmux-plugins/tmux-sensible\u0026#39; 20 21# ========================= 22# Catppuccin配置（可选优化） 23# ========================= 24set -g @catppuccin_flavour \u0026#39;mocha\u0026#39; # latte / frappe / macchiato / mocha 25 26# 状态栏位置 27set -g status-position bottom 28 29# ========================= 30# 初始化 TPM（必须放最后） 31# ========================= 32run \u0026#39;~/.tmux/plugins/tpm/tpm\u0026#39; 安装插件 # 进入tmuxtmux，然后Ctrl + a -\u0026gt;Shift + I\n等待自动安装 大写I 加载配置 # 1tmux source-file ~/.tmux.conf tmux使用 # 🟢 会话（session） # 1tmux new -s name # 创建会话 2tmux ls # 列出会话 3tmux attach -t name # 进入会话 4tmux kill-session -t name # 删除会话 5tmux rename-session -t old new 🔵 基本快捷键（前缀 Ctrl + a） # 1Ctrl + a d # detach（后台运行） 2Ctrl + a r # 重载配置（需绑定） 3Ctrl + a : # 命令模式 🟡 窗口（window） # 1Ctrl + a c # 新建窗口 2Ctrl + a n # 下一个窗口 3Ctrl + a p # 上一个窗口 4Ctrl + a 数字 # 切换窗口 5Ctrl + a , # 重命名窗口 6Ctrl + a w # 列出窗口 7Ctrl + a \u0026amp; # 关闭窗口 🟣 分屏（pane） # 1Ctrl + a % # 垂直分屏 2Ctrl + a \u0026#34; # 水平分屏 3Ctrl + a 方向键 # 切换 pane 4Ctrl + a x # 关闭 pane 5Ctrl + a z # 最大化/还原 pane 🟠 调整大小 # 1Ctrl + a Ctrl + ←/→/↑/↓ # 调整 pane 大小 🟤 布局 # 1Ctrl + a 空格 # 切换布局 2Ctrl + a Alt + 1 # even-horizontal 3Ctrl + a Alt + 2 # even-vertical 4Ctrl + a Alt + 3 # main-horizontal 5Ctrl + a Alt + 4 # main-vertical ⚫ 复制模式（vi） # 1Ctrl + a [ # 进入 copy-mode 2v # 开始选择 3y # 复制 4q # 退出 🎯 一句话速记 # 1session：tmux new -s 2退出不关：Ctrl+a d 3分屏：% 和 \u0026#34; 4切换：方向键","date":"2026-03-24","externalUrl":null,"permalink":"/p/tmux%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/","section":"技术博客","summary":"为什么用tmux：首先，因为我最近换了一个终端模拟器alacritty，这个模拟器不支持原生的分屏，需要通过tmux辅助。别问为什么非要用alacritty而不是自带分屏的ghostty，因为一个是rust一个是zig。 另外，我在使用服务器训练raft视觉模型的时候，偶尔因为网络断开连接，导致远程ssh关闭，自动的结束了训练，虽然我知道了可以使用nohup 在\u003e输出到log文件中，但是还是觉得如果可以用tmux这种会更方便。\n","title":"Tmux使用教程","type":"posts"},{"content":"why zsh: 本人长期使用bash，其实早有耳闻zsh的方便快捷，之前黄学长给我的使用的服务器里面就配置了zsh，当时感觉自动补齐功能很惊艳，但是受限于我原本在机器人队打工，很多网上开源雷达点云算法（pointlio，fastlio）都需要通过source setup.bash来配置环境，如果用zsh可能会有些问题，但最近很高兴去尝试一些新的东西，于是就有了这篇博客\nzsh的特点 # zsh，即z-shell，是在bourne-shell的基础上，作出许多改进的一种命令解释器，其实就是shell就是linux或者类linux架构中，起到和kernel内核传达指令的“壳”（shell）。 zsh是保罗（Paul Falstad）在普林斯顿大学求学期间编写的，当时只是初版，而zsh的名字是来源于他的一个老师邵中（zhong shao），保罗把他老师的名字zsh作为了shell的名称。 此后，zsh一直作为bash替代，不稳不火。2019年，由于macos上的bash版本太旧了，但是新版的bash采用GPLv3授权，这让苹果无法接受，自此苹果改成了zsh作为默认shell(依旧果子重拳出击)。 zsh有着更好的扩展性，同时可以定制更多的主题，让平平无奇的终端变得赏心悦目。 oh-my-zsh：一个免费好用，非常好用的开源zsh框架，由开源社区推动，现在已经有了很多非常好用的插件。比如git，zsh-autosuggestions，建议每一个人都无脑使用oh-my-zsh。 alacritty:一个使用rust编写基于opengl的终端模拟器，快、轻便、跨平台是他的特点，他相对于ghostty的缺点就是不能支持原生分屏，但这一点可以通过tmux弥补。其他全是优点。 安装zsh和oh-my-zsh # 下载 # 在ubuntu安装zsh可以直接用apt来安装\n1sudo apt update 2sudo apt install -y zsh git curl #顺便检查一下git和curl的安装在archlinux系列可以通过pacman安装\n1sudo pacman -S zsh安装完可以检查一下\n1which zsh 2zsh --verstion 配置 # 如果有需要，可以把zsh设置为默认的shell 通过执行这个命令可以完成设置\n1chsh -s \u0026#34;$(which zsh)\u0026#34;会要求你输入密码，然后退出重新打开终端，通过下面这个指令来确认是否切换成功。\n1echo $SHELL如果改完之后还是显示是原始的shell，bash或者fish，建议重启一下。\n安装oh-my-zsh # 直接用官方仓库(omz竟然有185.6k stars)给的脚本来安装。\n1sh -c \u0026#34;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34;然后可以使用下面的指令来安装两个最常用的插件\n1git clone https://github.com/zsh-users/zsh-autosuggestions \\ 2 ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 3 4git clone https://github.com/zsh-users/zsh-syntax-highlighting.git \\ 5 ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlightingclone完之后，还要去~/.zshrc中把plugins后面加上zsh-autosuggestions和zsh-syntax-highlighting，如下：\n1plugins=( 2 git 3 zsh-autosuggestions 4 zsh-syntax-highlighting 5)还要执行一下下面这两行，这两行是用来是zsh的自动补齐生效的。\n1autoload -Uz compinit 2compinit 安装starship(可选) # 这是一个终端美化工具，如果你本地有rust和cargo环境，可以直接用cargo来安装（如果没有rust，建议尝试一下安装rust，你不会后悔的）。\n1cargo install starship --locked如果没有也不用着急，starship官方还给了脚本安装的方式，curl -sS https://starship.rs/install.sh | sh 这个网址里面有很多别人配置好的预设，你如果有兴趣也可以自己配置。直接把别人的预设复制粘贴到下面这个toml文件内。\n1mkdir -p ~/.config 2nano ~/.config/starship.toml最后可以通过source ~/.zshrc来让自己的配置生效。\n安装主题： # 如果厌倦了原始简洁主题，可以尝试使用一下这个powerlevel10k，很好看的。安装方法是还是推荐clone到oh my zsh的目录，\n1git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k然后在.zshrc中找到ZSH_THEME那一行，改成这个\n1ZSH_THEME=\u0026#34;powerlevel10k/powerlevel10k\u0026#34;然后再source\n1source ~/.zshrc此时就会进入p10k的配置向导，如果没有自动进入可以手动进入\n1p10k configure在配置的过程中他会问你能否正常显示一些表情，所以在安装这个包之前最好先准备好支持等宽中文的表情字体，比如Maple Mono NF CN。\nMaple Mono NF CN 可以通过查看这个链接，我们从下图中可以看到，他会推荐使用ArchlinuxCN，我也去问了一下如何添加这个CN到paru源里面。 总共三步,编辑pacman：sudo nano /etc/pacman.conf，其次在文件最末尾添加， 1[archlinuxcn] 2Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch,最后在保存文件之后，通过这样的命令，\n1sudo pacman -Sy archlinuxcn-keyring此时就可以正常下载这个字体了。\n可能存在的问题 # 可能在安装并且设置好默认shell后发现没有改。 # 这个问题好像是ubuntu自带的终端一直存在的问题，就是没有办法去真正的改变他的shell，我自己也试过很多方法，最后都不行。 所以我给出的权宜之计就是使用其他的终端模拟器，就是我上面介绍的两个，anticritty或者ghostty，这两者相对来说，功能更完善的还是使用zig编写的ghostty，但是我还是推荐你使用anticritty，(别问为什么，问就是他是使用rust编写的，我是rust信徒。) 还有一种可能，就是需要logout之后在重新进入才能正确设置成zsh。\n","date":"2026-03-23","externalUrl":null,"permalink":"/p/zsh%E5%BC%80%E7%AE%B1%E5%8D%B3%E7%94%A8/","section":"技术博客","summary":"本文简单介绍了一下如何在linux（ubuntu24.04）上面安装zsh","title":"Zsh开箱即用","type":"posts"},{"content":" 工作流介绍。 # 工作流整体如图所示。\n首先是用户输入，对于用户输入的问题，使用一个参数提取器，调用glm-4.7模型对其进行参数提取，参数提取为year，region，task_type，keywords。为了方便的其他操作。 接着呢，就是一段代码执行块，执行了下面这一段python代码。主要实现的逻辑是，对于没有发布指定法规的年份，使用上一个最近的发布的法规，即对于2022徐州的问题，就返回2021年发布的支出标准。对于2026徐州就返回2025年发布的支出标准。 1def main(year: int, region: str, keywords: str): 2 REGULATIONS = [ 3 {\u0026#34;region\u0026#34;: \u0026#34;徐州\u0026#34;, \u0026#34;year\u0026#34;: 2021, \u0026#34;filename\u0026#34;: \u0026#34;徐州市政务信息化项目运维服务支出标准(徐财评〔2021〕5号).pdf\u0026#34;}, 4 {\u0026#34;region\u0026#34;: \u0026#34;徐州\u0026#34;, \u0026#34;year\u0026#34;: 2025, \u0026#34;filename\u0026#34;: \u0026#34;徐州市政务信息化项目运维服务支出标准(徐财评〔2025〕13号).pdf\u0026#34;}, 5 {\u0026#34;region\u0026#34;: \u0026#34;无锡\u0026#34;, \u0026#34;year\u0026#34;: 0, \u0026#34;filename\u0026#34;: \u0026#34;《无锡市市级政务信息化建设及运行维护项目预算支出标准(试行)》.pdf\u0026#34;}, 6 {\u0026#34;region\u0026#34;: \u0026#34;江苏省\u0026#34;, \u0026#34;year\u0026#34;: 2021, \u0026#34;filename\u0026#34;: \u0026#34;省政府办公厅关于印发江苏省省级政务信息化项目建设管理办法的通知(苏政办发〔2021〕24号).pdf\u0026#34;}, 7 {\u0026#34;region\u0026#34;: \u0026#34;辽宁\u0026#34;, \u0026#34;year\u0026#34;: 0, \u0026#34;filename\u0026#34;: \u0026#34;《辽宁省省级政务信息化建设项目预算支出标准规定(试行)》.pdf\u0026#34;}, 8 {\u0026#34;region\u0026#34;: \u0026#34;连云港\u0026#34;, \u0026#34;year\u0026#34;: 0, \u0026#34;filename\u0026#34;: \u0026#34;《连云港市市级政务信息化项目运维方案编制指南和支出预算标准(试行)》.pdf\u0026#34;}, 9 ] 10 FALLBACK_REGION = \u0026#34;江苏省\u0026#34; 11 12 # 1. 匹配地区 13 candidates = [r for r in REGULATIONS if region in r[\u0026#34;region\u0026#34;] or r[\u0026#34;region\u0026#34;] in region] 14 if not candidates: 15 candidates = [r for r in REGULATIONS if FALLBACK_REGION in r[\u0026#34;region\u0026#34;]] 16 17 # 2. 匹配年份 18 if candidates: 19 eligible = [r for r in candidates if r[\u0026#34;year\u0026#34;] \u0026lt;= year] 20 best = max(eligible, key=lambda r: r[\u0026#34;year\u0026#34;]) if eligible else None 21 else: 22 best = None 23 24 # 3. 拼接 query 25 if best: 26 filename_stem = best[\u0026#34;filename\u0026#34;].replace(\u0026#34;.pdf\u0026#34;, \u0026#34;\u0026#34;) 27 query = f\u0026#34;{filename_stem} {keywords}\u0026#34; 28 else: 29 # 无匹配时用基础信息兜底 30 query = f\u0026#34;{region} {year}年 {keywords}\u0026#34; 31 32 return { 33 \u0026#34;year\u0026#34;: str(year), 34 \u0026#34;filename\u0026#34;: best[\u0026#34;filename\u0026#34;] if best else None, 35 \u0026#34;query\u0026#34;: query, 36 } 接着，是一个llm节点，调用deepseekv3，根据得到的信息实现rag查询重写，为了方便在知识库中查找。以下为system提示词： 1你是一个面向向量检索（RAG）的查询重写专家。用户当前的需求是估算政务软件项目的造价。 2请根据用户的原始 query，将其拆解并改写为 2 到 3 个具体的【自然语言问句或短句】，以便在知识库中精准匹配到长文档中的计算公式和费率表。 3 4改写规则与约束： 51. 严禁堆砌关键词：绝对不要输出用空格隔开的零散词汇组合，必须是结构完整的自然语言。 62. 剥离业务噪音：将用户原始 query 中具体的业务场景（如“录入表单”、“财政业务”）抽象为通用的造价术语（如“定制软件开发”、“功能点测算”）。 73. 必须包含多路检索意图： 8 - 意图 A（找公式）：生成一句专门针对底层计算公式的检索词（如：“定制软件开发服务费用的计算公式是什么？”） 9 - 意图 B（找参数）：生成一句专门针对费率和取费标准的检索词（如：“软件开发生产率基准、人月折算系数和基准人月费率是多少？”） 10 11不要输出任何解释或思考过程，请直接分行输出优化后的自然语言查询句子。要明确年份和地区接下来就是知识检索，我将文件分成了两个知识库，一个是行业基准数据，一个是地方政策。索引方式都是高质量，使用zhipu的embedding-3模型，检索方式采用混合检索，使用有道的bcererankbaseV1模型，top-K设置为7。 接下来是变量聚合器，将上面查询两个数据库的结果合并起来。 最后，整合上面主要的信息，输入给llm节点，让他来进行最后的计算。该节点调用的是glm4.7,下面是他的提示词\n1# Role 2你是一位资深的政府信息化项目造价评估与审计专家。你的任务是根据提供的官方政策文件和行业基准数据，为软件开发或系统运维项目提供极其严谨、准确的成本估算。 3 4# Rules 51. **绝对忠实于上下文**：你必须【仅根据】提供的上下文（Context）中的公式、基准价格、系数进行计算。严禁使用任何外部知识或自行编造单价。 62. **处理信息缺失**：如果上下文中缺乏计算必需的参数（如某个特定表单的复杂度权重、特定级别工程师的单价等），请明确指出缺失的内容，并根据已有信息给出一个合理的估算范围，或仅列出计算公式。 73. **展现思维链（CoT）**：所有的计算必须有明确的推导过程，不能直接抛出结果。必须先列出公式，再代入数据，最后得出结果。 84. **单位统一**：请在计算过程中注意单位的统一（如“元”、“万元”、“人月”、“人年”等），并在最终结果中清晰标注。 9 10# Output Format 11请严格按照以下四个部分输出你的解答： 12**1. 需求解析**：简述项目年份、所属地域、项目类型（开发/运维）及关键规模参数（如表单数、接口数、驻场人数等）。 13**2. 评估依据**：明确列出你从上下文中提取到的用于计算的具体文件名称、计算公式、基准单价和相关系数。 14**3. 计算过程**：将需求参数代入公式，一步步进行数学运算。 15**4. 最终估算**：给出一个明确的总价（或价格区间），并附上一句简短的专业风险提示或建议。 运行测试 # 输入问题 # 2022年3月，徐州市财政局要开发一套财政业务管理系统，包括3个录入查询表单，每个表单分别对应3个数据库的表和一个外部接口，请估算合理的价格范围；\n输出结果 # 1**1. 需求解析** 2 3- **项目年份**：2022年3月（依据上下文规则，采用2021年度基准数据）。 4- **所属地域**：徐州市（注：上下文提供的人月费率基准为无锡市数据，计算中将暂用此基准，并在建议中提示地域差异）。 5- **项目类型**：新建软件开发项目（财政业务管理系统）。 6- **规模参数**：包含3个录入查询表单。每个表单对应3个数据库表（共计9个内部逻辑文件参考对象）和1个外部接口（共计3个外部接口参考对象）。 7 8**2. 评估依据** 9根据提供的上下文（《江苏省省级财政投资评审项目支出预算标准》及相关引用文件），本次估算依据如下： 10 11- **计算模型**：采用功能点法进行成本估算。 12- **人月折算系数**：174 人·时/月。 13- **软件开发生产率基准（P50）**：6.32 人·时/功能点（电子政务领域）。 14- **生产率浮动范围**：根据实际情况可上下浮动 20%（即 5.056 ~ 7.584 人·时/功能点）。 15- **复用度调整系数**：新建项目预算阶段默认取值范围为 0.75 - 1（复用度低）。 16- **软件开发基准人月费率**：24,000 元/人·月（参考上下文中无锡市平均基准）。 17- **缺失参数说明**：上下文中未提供具体的“功能点计数规则”（即未定义表单、数据库表、接口分别对应多少功能点），因此无法直接将业务需求数量转换为功能点总数。以下计算将基于**“单功能点单价”**进行推导。 18 19**3. 计算过程** 20 21**步骤一：计算基准工时单价** 22根据人月费率和人月折算系数，计算每小时的直接人力成本单价： 23 24$$ 25\\begin{aligned} 26\\text{基准工时单价} \u0026amp;= \\frac{\\text{软件开发基准人月费率}}{\\text{人月折算系数}} \\\\ 27\u0026amp;= \\frac{24,000 \\text{ 元/人月}}{174 \\text{ 人·时/人月}} \\\\ 28\u0026amp;\\approx 137.931 \\text{ 元/人·时} 29\\end{aligned} 30$$ 31 32**步骤二：计算单功能点成本范围（未考虑复用度）** 33结合生产率基准及浮动范围（±20%），计算单个功能点的开发成本： 34 35- **生产率下限（效率最高）**：$6.32 \\times (1 - 20\\%) = 5.056 \\text{ 人·时/FP}$ 36- **生产率上限（效率最低）**：$6.32 \\times (1 + 20\\%) = 7.584 \\text{ 人·时/FP}$ 37 38- **单功能点成本下限**： 39 $$ 137.931 \\text{ 元/人·时} \\times 5.056 \\text{ 人·时/FP} \\approx 697.36 \\text{ 元/FP} $$ 40- **单功能点成本上限**： 41 $$ 137.931 \\text{ 元/人·时} \\times 7.584 \\text{ 人·时/FP} \\approx 1,046.03 \\text{ 元/FP} $$ 42 43**步骤三：应用复用度调整系数** 44针对新建项目，复用度调整系数范围为 0.75 - 1。我们需要计算最终的单功能点综合单价区间。 45 46- **最低单价**（生产率下限 $\\times$ 最低复用度）： 47 $$ 697.36 \\times 0.75 \\approx 523.02 \\text{ 元/FP} $$ 48- **最高单价**（生产率上限 $\\times$ 最高复用度）： 49 $$ 1,046.03 \\times 1.00 = 1,046.03 \\text{ 元/FP} $$ 50 51**步骤四：项目总规模估算（功能点推导）** 52_由于上下文缺乏具体的“功能点计数表”，无法精确计算规模。以下为基于行业常见理解（非上下文数据，仅供参考逻辑）的公式化表述：_ 53 54若设该项目的总功能点数为 $S$，则总价计算公式为： 55$$ \\text{项目总费用} = S \\times \\text{单功能点综合单价} $$ 56 57**4. 最终估算** 58 59由于提供的上下文中**缺失功能点计数标准**（即无法确定“3个表单”、“9个数据库表”、“3个接口”具体折算多少功能点），无法直接得出具体的总价。 60 61基于上下文数据，该项目的**单功能点综合单价应在 523.02 元 至 1,046.03 元 之间**。 62 63_若假设_（仅为举例，非依据上下文）该项目总规模为 100 功能点，则总价估算范围为： 64$$ 52,302 \\text{ 元} \\leq \\text{总价} \\leq 104,603 \\text{ 元} $$ 65 66**专家风险提示与建议：** 67 681. **地域差异**：计算依据使用了上下文中的“无锡市”平均基准人月费率（2.4万元/人月）。徐州市的实际费率可能与此存在差异，建议查询徐州市当地发布的最新信息化项目造价标准进行替换。 692. **标准缺失**：目前最关键的是缺乏《软件工程 功能规模测量》等具体的计数规则文件，建议补充“表单”、“数据表”与“功能点”的对应换算表，以完成精确的规模测算。 703. **非人力成本**：上述估算仅包含软件开发的人力及间接成本，未包含直接非人力成本（如软硬件采购、差旅费等），如有此类支出需另行计算。 输入问题 # 2026年，徐州公安局要开发一套警察人员管理系统，包括3个录入查询表单，每个表单分别对应3个数据库的表和一个外部接口，请估算合理的价格范围；\n输出结果 # 1 * **1. 需求解析：** 2 * 年份：2026年。 3 * 地点：徐州（江苏）。*注：上下文使用的是辽宁费率。* 4 * 类型：完全定制开发（J0401）。 5 * 规模：3个表单，3个数据库表，1个外部接口。 6 * **2. 评估依据：** 7 * 文件：“5.软件开发费”，表1。 8 * 方法：完全定制开发。 9 * 公式：定制开发费用 = 人月费率 × 开发工作量。 10 * 费率：1.87万元/人月。 11 * 注意：原则上应使用功能点法，但上下文缺少功能点计数规则和基准生产率。 12 * **3. 计算过程：** 13 * 假设“开发工作量” = X 人月。 14 * 计算：1.87 * X。 15 * 由于我无法计算X（需要“功能点数”和转换系数），计算停在这里。 16 * 确立人月单价。 17 * **4. 最终估算：** 18 * 结果：无法确定总价。 19 * 确定费率：**18,700元/人月**。 20 * 建议：建议在徐州当地重新评估费率，并确定工作量（可能通过功能点分析）。 21 22- _等等，再看“用户的具体项目需求”。_ “请估算合理的价格范围。” 23- 如果用户*期待*一个数字，并且我提供不了，我需要非常有条理。 24- 有*任何*可能“接口”或“表单”有隐含成本吗？不。 25- _修正：_ 我将提供计算**如果**工作量已知的结构，并强调1.87万这个数字。 26 27- _让我们最后一次检查提示指令。_ “如果上下文缺乏... 给出合理的估算范围，或仅列出公式。” 28- 既然我不能编造范围，我将“仅列出公式”并提供“单价”。 29 30- _完善后的输出结构：_ 31 - **1. 需求解析**：清楚地陈述徐州2026年项目的细节。提到地域不匹配（徐州 vs 辽宁）。 32 - **2. 评估依据**：引用“完全定制开发”方法和具体的“1.87万元/人月”费率。引用功能点优先但数据缺失。 33 - **3. 计算过程**： 34 - 公式：`总价 = 人月费率 × 开发工作量`。 35 - 已知：`人月费率 = 1.87万元/人月`。 36 - 未知：`开发工作量`。解释为什么未知（没有功能点表/工作量表）。 37 - 数学：展示单价是18,700。 38 - **4. 最终估算**： 39 - 由于变量缺失，无法计算总价。 40 - **有效单价：** 18,700元/人月。 41 - **风险/说明：** 地域差异（辽宁费率应用于江苏），以及缺少工作量估算参数。 42 43- _自我修正/完善：_ 提示要求我成为“资深专家”。资深专家不仅仅是说“我不能”。他们会说“基于提供的数据，我们建立了单位成本模型。然而，要得出总价，我们需要通过[缺失方法]确定工作量。基于现有数据，单位成本如下...” 44- 这是最稳健的回答方式。它遵循规则（不编造工作量），但回答了请求的“精神”（估算成本 = 确立费率）。 45 46- _再检查一次：_ “接口”算作“商品软件”吗？不，通常是定制。“表单”呢？定制。 47- _等等_，“商品软件费用”提到“∑商品软件单价×数量”。项目没有提到购买商品软件（如Oracle许可证或成品系统）。所以“商品软件费用”为0。 48- _等等_，“分级部署费用”？文本说“完全定制开发... — — 定制开发费用”。所以不涉及分级部署费用或商品软件费用。 49 50- _逻辑的最终检查：_ 51 1. **项目**：完全定制开发。 52 2. **费用公式**：人月费率 × 开发工作量。 53 3. **费率**：1.87万元/人月（根据提供的文本）。 54 4. **工作量**：未知/缺失。 55 5. **结论**：成本 = 1.87 \\* 工作量。 56 57- _格式：_ 按要求使用四个部分。 58 59- _关于“3年”条款的一个细节？_ 不，提示说“开发一个系统”。这不是租赁或运维项目（尽管提到“1年维保”）。合同“可能”是3年（租赁），但这里“开发”意味着建设。 60- _输出语言：_ 中文，专业语气。 61 \u0026lt;/think\u0026gt;**1. 需求解析** 62- **项目年份**：2026年 63- **所属地域**：江苏省徐州市（注意：参考文件数据基于辽宁省，存在地域基准差异） 64- **项目类型**：定制软件开发服务（完全定制开发，J0401） 65- **关键规模参数**：包含3个录入查询表单、3个数据库表、1个外部接口。 66 67**2. 评估依据** 68根据提供的参考上下文，提取以下计算标准： 69 70- **服务类别**：完全定制开发。 71- **费用构成公式**：`定制开发费用 = 人月费率 × 开发工作量`（见上下文第3条“完全定制开发”计算方法及（1）工作量估算法）。 72- **人月费率标准**：根据上下文，软件开发人员的人月费率标准为 **1.87 万元/人月**。 73- **功能点法补充说明**：上下文提到“原则上按功能点法估算”，且提供了功能点法的复杂公式，但未提供具体的“功能点数对应表”、“基准生产率”、“人月折算系数”或“应用类型调整因子”的具体数值。因此，无法采用功能点法进行直接计算，只能采用工作量估算法列出公式。 74- **其他费用**：项目无商品软件购置或分级部署费用，仅计算定制开发费用。 75 76**3. 计算过程** 77由于上下文中未提供“录入查询表单”、“数据库表”或“外部接口”对应的“开发工作量”（人月）折算标准，无法直接计算最终总价。以下基于已知参数建立费用模型： 78 79**第一步：确定基础单价** 80根据上下文中辽宁省的数据标准： 81 82- 人月费率 = 1.87 万元/人月 83 84**第二步：建立计算公式** 85根据完全定制开发的费用计算规则： 86 87- 定制开发费用 = 1.87 万元/人月 × 开发工作量（人月） 88 89**第三步：分析缺失参数** 90要得到具体总价，需要确定“开发工作量”。 91 92- 若采用工作量估算法：需要知道3个表单、3个数据库表、1个接口具体需要多少个人月来完成。上下文中未提供这些组件的工时基准（如：每个表单开发需要0.5人月等）。 93- 若采用功能点估算法：需要先计算功能点数，并代入公式： 94 `费用 = 功能点数 × 规模变更调整因子 × 基准生产率 / 人月折算系数 × 应用类型调整因子 × 人月费率` 95 但上下文未提供上述各调整因子的具体数值，且未提供“表单”与“功能点”的转换规则，故此路径无法计算。 96 97**4. 最终估算** 98由于上下文缺失关键参数（组件与工作量/功能点的对应关系及调整系数），无法给出具体的总价数值。 99 100**估算结论**： 101该项目每投入 1 个开发人月，成本为 **1.87 万元**。 102建议按照以下公式进行最终测算： 103 104\u0026gt; **总价（万元） = 1.87 × 预估开发人月数** 105 106**专家风险提示**： 107 1081. **地域差异风险**：提供的人月费率（1.87万元/人月）明确基于辽宁省统计数据，而项目位于江苏徐州。通常江苏省的人工成本高于辽宁省，直接使用该费率可能导致估算偏低，建议结合江苏省或徐州市当地的同类项目标准调整费率。 1092. **工作量测算缺失**：在缺乏具体功能点计费规则的情况下，建议通过专家评审法（如德尔菲法）对3个表单和1个接口的开发工作量进行人天评估，再代入上述公式计算。","date":"2026-03-23","externalUrl":null,"permalink":"/notes/dify%E5%88%9D%E4%BD%93%E9%AA%8C1/","section":"知识笔记","summary":"工作流介绍。 # 工作流整体如图所示。\n","title":"Dify初体验1","type":"notes"},{"content":"","date":"2026-03-22","externalUrl":null,"permalink":"/tags/cv/","section":"Tags","summary":"","title":"CV","type":"tags"},{"content":"","date":"2026-03-22","externalUrl":null,"permalink":"/tags/dl/","section":"Tags","summary":"","title":"DL","type":"tags"},{"content":" 前情提要 # 什么是RAFT # RAFT-stereo是基于RAFT的扩展。RAFT即Recurrent All-Pairs Field Transforms，是一个很出名的光流估计模型，他的特点是先建立全局匹配关系，再通过循环迭代不断细化结果，每一步更新都会变得更准，而RAFT-stereo是基于这个模型的双目改造。 RAFT-stereo的原理 # 先用卷积网络提取左右图的高维特征，而不是拿RGB去比较。因为原始RGB容易受到光照，纹理，噪声影响。 接着就是构建相关性体，简单说就是对于左图中的每一个位置，它都会和右图的一整条去进行相似度比较，形成一种“匹配代价”。 再接着就是不断迭代，他会先给个初始估计，然后通过循环更新模块来反复修正。\n和其他立体匹配有什么不同之处 # 传统方法，比如SGM、Blocking Matching，是先算匹配代价，再代价聚合，再做视觉选择，最后再做左右一致性检查。 而RAFT-stereo，属于端到端的学习方法，他会自动学习，什么特征适合匹配，什么区域应该相信上下文，哪些遮挡、弱纹理、重复纹理区域该怎么处理。\n为什么做这个 # 我的本科毕业设计做的是双目摄像头的，通过资料搜集，我发现网上感觉最新（2021年提出）的双目摄像头立体匹配算法就是这个RAFT-Stereo，于是我便接触到了这个项目。\n训练过程 # 首先，这个项目已经被开源到Github,而且readme文档有较为详细的指令包括下载数据集，demo输出，train，evaluate等等。 说实话，这是我第一次进行正式的模型训练和微调项目，之前做过的模型训练是yolov5，之前g308（西南交通大学robocon校队，我梦开始的地方，没有这个机会，我根据不会接触技术路线，这个博客也不会诞生）的入队考核需要通过这个进行蓝球，红球，球框额的识别（实际上就是robocon2024的麦穗题目），每个人都会以自己的方式接触到yolo，都是回忆啊，在这个之后我就没有做过需要模型训练的项目了，而且就算是那个yolo项目，我也没有进行模型微调，毕竟是入队考核，还是以基础为主。 通过这个项目，chatgpt辅助我，让我也学会了大致的模型微调流程，以下是我的总结\n首先要对原始模型进行推理和评测，得到baseline，也就是整个微调的基线。 然后控制变量，每次只改一部分，而且要保留原模型，改动要作为一个选择，也就是作为运行程序的一个可选参数，而不能直接在原模型上改，不然的话，感觉就没有回头路了。 再然后就是根据评价指标，对得到的模型进行评价，和baseline对比。 模型改进改动 # 对于模型改变,我只是根据chatgpt给的提示作了一些修改，代码全部上传到我自己fork的github上，\nrefinement # 我首先尝试了增加一个refinement层,这是一个很微小的改变,以下为refinement层\n1import torch 2import torch.nn as nn 3import torch.nn.functional as F 4 5class RefinementHead(nn.Module): 6 def __init__(self, in_channels=4, hidden_dim=32): 7 super(RefinementHead, self).__init__() 8 self.conv1 = nn.Conv2d(in_channels, hidden_dim, 3, padding=1) 9 self.conv2 = nn.Conv2d(hidden_dim, hidden_dim, 3, padding=1) 10 self.conv3 = nn.Conv2d(hidden_dim, hidden_dim, 3, padding=1) 11 self.conv4 = nn.Conv2d(hidden_dim, 16, 3, padding=1) 12 self.conv5 = nn.Conv2d(16, 1, 3, padding=1) 13 14 def forward(self, image1, disp): 15 x = torch.cat((image1, disp), dim=1) 16 x = F.relu(self.conv1(x)) 17 x = F.relu(self.conv2(x)) 18 x = F.relu(self.conv3(x)) 19 x = F.relu(self.conv4(x)) 20 res = self.conv5(x) 21 return disp + res实际上RAFT-Stereo最核心的组件就是内置的精炼层\u0026mdash;-多层卷积GRU，这样的设计本身就是在精炼，所以第一步的视差估计都是粗糙的，每一步都在上一步的基础上迭代、修正，最后一轮的输出就是经过了32次迭代的输出。 refinement是什么，本质上是一个输出端的残差修正模块，在RAFT-Stereo经过多次迭代后，会输出一个目前比较好的视差图，然后再和输入的左图拼接，\n左图：3通道 视差图：1通道 得到了一个4通道的输入，将其输入到refinement head模块中，就是上面的代码块中，最终得到一个1通道残差图，每个像素点表示此处应该对视差作出的更改。 1if hasattr(self.args, \u0026#39;use_refinement\u0026#39;) and self.args.use_refinement: 2 disp0 = flow_predictions[-1] 3 disp_refined = self.refinement_head(image1_raw / 255.0, disp0) 4else: 5 disp_refined = flow_predictions[-1]我的refinement主要想解决的问题是物体边界存在模糊、细节构区域。所以这个模块更像是图像引导的局部视差修正器。\n边缘感知损失 # 边缘感知损失本质上让模型在图像边缘附近犯错时付出更大的代价。将普通的L1 loss计算从$L= |d_{pred}-d_{gt}|$ 变成 $L_{edge}=weight*|d_{pred}-d{gt}|$\n1if args.use_edge_loss: 2 loss_edge = edge_aware_loss(disp_refined, flow, valid, image1) 3 loss += args.lambda_edge * loss_edge 4 metrics[\u0026#34;loss_edge\u0026#34;] = loss_edge.item()那么问题是，如何找到图像边缘位置呢，按照以下步骤：把RGB转成灰度图-\u0026gt;算出图像梯度-\u0026gt;归一化-\u0026gt;构造最终权重。 最终权重计算公式：\n$$ weight = 1.0 + \\alpha *grad $$该方法的原理是，视觉误差并不是所有位置都一样重要，在平坦区域，误差稍微大一点，视觉上可能还不明显。但在边界区域，只要错一点点，就会造成：\n轮廓糊掉 深度断层错位 物体边缘拉扯 细结构消失 我的代码整个总损失是由三部分组成，首先是原始的sequence loss，是RAFT-Stereo自带的损失，其次是refined loss，是最终的视差图和gt的普通误差监督，最后是edge-aware loss，这个是对 disp_refined 在边缘区域加权后的误差监督。\npartial unfreeze # 之前的训练都是冻结整个RAFT-Stereo主干，之训练了新增的，refinement head，但是partial unfreeze呢，仍然保留大部分主干冻结，额外解冻update_block，让refinement_head和update_block一块训练。 实验结果 # EPE D1 Baseline 2.3758 12.0526 Refinement only 2.3760 12.0609 Refinement + Edge Loss 2.3757 12.0588 Partial Unfreeze 2.4376 12.5331 从结果可以看出，仅增加 refinement head 或加入边缘感知损失后，模型整体性能与 baseline 基本持平，未出现明显提升，但也没有显著破坏原始模型性能。这说明输出端的轻量级局部修正结构在当前小规模真实域数据集设置下，对整体 EPE 和 D1 指标的影响较为有限。\n相比之下，partial unfreeze 策略使模型性能出现明显下降。这说明在仅使用 Middlebury 小规模数据集进行微调时，解冻 update block 会显著增加过拟合风险，并可能破坏原始预训练模型已经形成的匹配更新能力，导致整体泛化能力下降。\n后续 # 在尝试提升模型性能无望后，我和导师商量过后决定把研究中心转移到对模型的轻量化上面来，当前模型大概有11.14m个参数，可以尝试剪枝和蒸馏，对模型进行“减重”，方便模型部署到低算力的边缘设备上。\n碎碎念 # 服务器 # 我这次训练都是使用autodl的服务器（不是广告），原本我以后这种租服务器，每次都是要把数据上传到服务器端，然后再开始跑模型，受限于网速，每次部署都会很浪费时间，如果一直挂着服务器，钱包又会受不了。实际上，这个服务器端，有三种存储形式，系统盘，数据盘和文件存储，其中系统盘就是镜像装配的盘，也就是整个系统配置所在的盘，你可以把一些数据文件放在里面，但是这个盘的大小通常不大，所以大数据不适合放在里面，但是这个有一个很大的有时就是，你可以上传自己的容器示例。 上传的实例可以非常方便的部署到同型号或者近似型号的显卡上。\n训练命令 # 我原本是直接使用python train.py 布拉布拉的配置信息，但是这个有一个问题，就是一旦我的网络不稳定，与服务器断开连接，运行的程序会因为终端的关闭而直接终止，因为这种连接本质都是ssh，而ssh就是将服务器的终端直接投到本地，倘若连接关闭，ssh会自动杀死服务器终端。当时的解决方案就是使用nohup（no hang up，不挂起）是告诉linux系统，后台不挂断地运行命令，此时退出终端也不会影响程序进行。\n1nohup python train_stereo.py \\ 2 --name raftstereo_partial_unfreeze_500 \\ 3 --restore_ckpt models/raftstereo-middlebury.pth \\ 4 --batch_size 1 \\ 5 --train_iters 16 \\ 6 --valid_iters 16 \\ 7 --num_steps 500 \\ 8 --mixed_precision \\ 9 --use_refinement \\ 10 --use_edge_loss \\ 11 --partial_unfreeze \\ 12 --lr_refine 2e-4 \\ 13 --lr_update_block 2e-5 \\ 14 --lambda_ref 1.0 \\ 15 --lambda_edge 0.2 \\ 16 --train_dataset middlebury \u0026gt;111.logs 2\u0026gt;\u0026amp;1 \u0026amp;希望以后能记住这个指令。更希望自己能擅长使用tmux。\n总算可以好好休息一下，前段时间还是有点太忙了。\n","date":"2026-03-22","externalUrl":null,"permalink":"/p/raft%E8%AE%AD%E7%BB%83%E6%97%A5%E5%BF%971/","section":"技术博客","summary":"前情提要 # 什么是RAFT # RAFT-stereo是基于RAFT的扩展。RAFT即Recurrent All-Pairs Field Transforms，是一个很出名的光流估计模型，他的特点是先建立全局匹配关系，再通过循环迭代不断细化结果，每一步更新都会变得更准，而RAFT-stereo是基于这个模型的双目改造。 ","title":"Raft训练日志1","type":"posts"},{"content":"","date":"2026-03-20","externalUrl":null,"permalink":"/tags/hugo/","section":"Tags","summary":"","title":"Hugo","type":"tags"},{"content":"","date":"2026-03-20","externalUrl":null,"permalink":"/categories/misc/","section":"分类","summary":"","title":"Misc","type":"categories"},{"content":"你好，这是我的博客 🚀\n放一张linus的照片 ","date":"2026-03-20","externalUrl":null,"permalink":"/diary/%E6%88%91%E7%9A%84%E7%AC%AC%E4%B8%80%E7%AF%87%E5%8D%9A%E5%AE%A2/","section":"日记","summary":"你好，这是我的博客 🚀\n放一张linus的照片 ","title":"我的第一篇博客","type":"diary"},{"content":"","date":"2022-03-06","externalUrl":null,"permalink":"/page/","section":"Example Category","summary":"","title":"Example Category","type":"page"},{"content":"","date":"2022-03-06","externalUrl":null,"permalink":"/archives/","section":"Example Category","summary":"","title":"归档","type":"page"},{"content":"","externalUrl":null,"permalink":"","section":"","summary":"","title":"","type":"authors"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":" Global unlock\n解锁私密文章 输入一次密码后，当前浏览器会话中的加密文章会自动解锁。 解锁 清除解锁状态 加密文章 # 加密内容试点 2026-05-10 私密日记 ","externalUrl":null,"permalink":"/private/","section":"Example Category","summary":" Global unlock\n解锁私密文章 输入一次密码后，当前浏览器会话中的加密文章会自动解锁。 解锁 清除解锁状态 ","title":"私密文章","type":"page"},{"content":"请使用页面顶部导航栏里的搜索按钮。\n","externalUrl":null,"permalink":"/search/","section":"Example Category","summary":"请使用页面顶部导航栏里的搜索按钮。\n","title":"搜索","type":"page"},{"content":"欢迎来到我的友链页面！\nsomnus 的 GitHub：我的个人代码仓库，主要分享计算机视觉、深度学习、ROS 开发以及 C++/Rust 相关的项目与学习记录。 leon 的 X (Twitter)：分享技术日常与生活动态，欢迎来找我交流互动！ ","externalUrl":null,"permalink":"/%E5%8F%8B%E9%93%BE/","section":"Example Category","summary":"欢迎来到我的友链页面！\nsomnus 的 GitHub：我的个人代码仓库，主要分享计算机视觉、深度学习、ROS 开发以及 C++/Rust 相关的项目与学习记录。 leon 的 X (Twitter)：分享技术日常与生活动态，欢迎来找我交流互动！ ","title":"友链","type":"page"}]