<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Bauklotze&apos;s World</title><description>墙壁的那边,有大海</description><link>https://bauklotze.vercel.app</link><item><title>A Little Attack Game</title><link>https://bauklotze.vercel.app/blog/alpha-lab/a-little-attack-game/a-little-attack-game</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/alpha-lab/a-little-attack-game/a-little-attack-game</guid><description>不只看分数：用 solve、attack、adjudicate 三阶段实验，比较 Muse、Gemini、GLM 与 Sol 在科研工作流中的角色。</description><pubDate>Sat, 05 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;前天突然更新了gemini3.8 flash以及我们的muse-spark-1.3 模型，考虑到就是我们测试一个模型，仅仅看他们的分数是不够的，比如像artificial intelligence指标，如果只看分数，可能只能看到，哦，muse-spark-1.3比较的牛逼，哦，我们的3.8flash好像指标挺厉害的，但是到底我们的不同的模型，只看指标显然是不成立的，但是如果我们去使用他去做任务，我也相信不太会有人在拥有gpt5.6 sol的情况下，还要去使用我们的3.8flash去跑你的真正的实验室任务(大家都担心会跑出来一坨狗屎)，然后去测试模型性能的。&lt;/p&gt;
&lt;p&gt;因此也自然出现了像跑鹈鹕蹬自行车这种的任务，但是我们又考虑到，这种任务仅仅是考察模型全面性，对于前端开发的那种人员而言可能是比较的合适的，但是到底什么任务对于我们科研人员是最最重要的呢，模型推理任务，从数据中去进行规律的分析，对于一个具体的任务的长程的推理，到底模型的insight怎么样，当前的模式最最适合的是哪一个部分呢，个人的感觉是，即使你的aritificial Intelligence 差个那么几分，但是模型于模型的内部的思考模式的不同给用户的体验，要远远大于我们的那几分。glm可能适合写代码，gpt可能适合作为reviewer,但是到底每一个新模型，体感如何，适合放到哪里呢，这些真正的对于每一个人的体感的问题，是因人而异的，是真正的和所谓的artificial intelligence指标不一样的，是我们的评判模型对于科研中是否好用的最核心的指标。&lt;/p&gt;
&lt;p&gt;因此我就做了这样的一个简单的测试的框架或者思路吧，也就是: 通过具体的数学问题的表现，去判断模型的真正的性能，我们的核心insight就是通过创造一个类似于竞技场的环境，让几个模型一起去进行解题，最后去进行性能的相互比较，类似月arena.ai 但是我们这里是偏向于真实科研种可能用到的具体ai能力，而不仅仅是几个指标。&lt;/p&gt;
&lt;p&gt;全部的我的测试的session源文件，题目以及整个结果分析，都放到了github上面去 &lt;a href=&quot;https://github.com/wesleyfei1/little-attack-game&quot;&gt;little-attack-game&lt;/a&gt; ,欢迎大家去star star&lt;/p&gt;
&lt;h2&gt;测试的framework&lt;/h2&gt;
&lt;p&gt;具体流程是 ,如果需要去测试模型A&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;default trusted but not intelligent model： gpt 5.6 sol max&lt;/li&gt;
&lt;li&gt;stage1: 一些相对简单的题目(当然，这个题目也是困难的题目，这里的简单题目指的是有答案的题目), 无论是使用A去进行问题的寻找(red-team tests),还是使用默认的一些搜索出来的题目，保存所有的中间的，包括模型的思考路径，包括模型的结果&lt;/li&gt;
&lt;li&gt;stage2: 困难的题目(包括近期刚刚有证明的数学猜想，以及来自于少年班学院24级的大佬&lt;strong&gt;srz&lt;/strong&gt;的题目&lt;strong&gt;RZBench&lt;/strong&gt;，包括来自几何拓扑，代数，等等领域的困难猜想)，用于验证模型有没有提出猜想，猜想的广度以及进行正确的验证的能力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有的过程种，用subagent去模拟一个sandbox环境(反代api有点点的危险，可以考虑使用pi,最轻量化的，避免prompt本身的影响)，给任何的subagent 15min的时间去解决一个问题，一个专属工作区，允许任何工具调用以及代码运行(gpu提供)，但是唯一要求是产出一份answer.md&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stage3: 根据上述的答案，去进行一个评测，并且针对于评测过程种，尤其是stage2种的模型表现去进行针对性的方案设计
&lt;ul&gt;
&lt;li&gt;比如muse-spark-1.3擅长于reflection,因此将stage2的评论的角色改成muse-spark-1.3,然后再让gpt5.6 sol回去进行评测&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过以上的过程，可以真正的通过一个精简的测试，得到关于一个模型到底应该充当科研过程种的哪一个环节的详细报告,通过创造一个类似于llm arena的竞技场的环境，最后得到，到底我们的每一个模型，再我们的claim提出，执行，以及最后的反思的一整个流程中最合适的是什么&lt;/p&gt;
&lt;h2&gt;最后的一个结论&lt;/h2&gt;
&lt;p&gt;我们横向对比了glm5.3, gemini3.8 flash,muse-spark-1.3,gpt 5.6 sol max以上的几个模型，为什么没有比较更多的模型因为平时以上的是我的主力模型，关于常见的deepseek v4 flash/pro的模型，以及kimi k3的话，等到之后有米了再去进行相应的测评&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;settings&lt;/strong&gt;: 主要目的是为了去评测我们的muse-spark-1.3, 因为他的aa指标最高(虽然现在看上去简直像一个笑话)，但是不可否认是一个好model,合理找到它的定位是我们的关键&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stage 1: muse-spark-1.3去进行题目的寻找，总共30个题目，所有的题目一起去进行一个评估&lt;/li&gt;
&lt;li&gt;stage 2: muse-spark-1.3首先去寻找了5道开放的那种问题(包括近几年才被证明出来的定理，以及一些还没有确定答案的猜想)，然后所有的模型15min内区进行回答&lt;/li&gt;
&lt;li&gt;stage3: 经过上一轮的发现，muse-spark再reflection方面有独特的优势，因此考虑将stage2中所有的模型的答案由muse重新测评，然后进行一个回复&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;结果分析&lt;/h2&gt;
&lt;h3&gt;stage1：先看看它会不会做，以及会不会怀疑题目&lt;/h3&gt;
&lt;p&gt;| model            |    实际作答范围 |             结果 | 其中比较关键的事情                                         |
| ---------------- | --------------: | ---------------: | ---------------------------------------------------------- |
| muse-spark-1.3   |      完整 30 题 | 28 PASS / 2 FAIL | Q23 是真正的证明缺口；Q30 找到反例 &lt;code&gt;n=171&lt;/code&gt;，反而证伪了标答 |
| gpt-5.6-sol      | 只横测 Q23、Q30 |         Q23 PASS | 同样确认 &lt;code&gt;171&lt;/code&gt;，证明收口最稳定                             |
| gemini-3.8-flash | 只横测 Q23、Q30 |         Q23 PASS | 同样确认 &lt;code&gt;171&lt;/code&gt;，局部推理和展开都不错                       |
| glm-5.3          | 只横测 Q23、Q30 |         Q23 FAIL | 能确认 &lt;code&gt;171&lt;/code&gt;，但唯一性论证仍然出了问题                     |&lt;/p&gt;
&lt;p&gt;这一轮最直观的结果是，muse的基础执行能力的确很强，但是“结论做对”和“证明真正闭合”仍然是两件事。sol和gemini在Q23上更稳，glm比较像愿意动手算的worker，但是证明本身需要再检查。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;真正让我注意到的并不是28/30，而是muse会主动怀疑ground truth：Q30不是模型做错了，而是模型把标答掀了。&lt;/strong&gt; 因此下一轮我想看的就不再只是有答案的题，而是当答案本身不确定的时候，不同模型到底会怎么工作。&lt;/p&gt;
&lt;h3&gt;stage2：把四个模型放到开放问题里面&lt;/h3&gt;
&lt;p&gt;其中S/A/B/C分别记为4/3/2/1分。&lt;/p&gt;
&lt;p&gt;| model            | Q1 Berge | Q2 ZCP | Q3 Kaplansky | Q4 Falconer | Q5 capset |  total |
| ---------------- | -------: | -----: | -----------: | ----------: | --------: | -----: |
| gpt-5.6-sol      |        S |      S |            S |           S |         S | &lt;strong&gt;20&lt;/strong&gt; |
| gemini-3.8-flash |        S |      B |            C |           B |         A | &lt;strong&gt;12&lt;/strong&gt; |
| muse-spark-1.3   |        B |      A |            B |           A |         C | &lt;strong&gt;11&lt;/strong&gt; |
| glm-5.3          |        B |      C |            B |           C |         B |  &lt;strong&gt;8&lt;/strong&gt; |&lt;/p&gt;
&lt;p&gt;sol的特点是比较克制，但是每一步基本都能闭合；gemini最会发散，能够很快铺开很多方向，不过偶尔会把没有真正验证的东西说得太满。muse比较务实，也最愿意标清楚自己做到了哪里，而且它又一次发现Falconer题面的阈值应该是&lt;code&gt;d/2&lt;/code&gt;；glm则最像计算worker，愿意留下代码和失败记录，但是代码可靠性仍然需要review。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这里开始出现了我们的核心假设：平均分可能低估“主动纠错”这种能力。muse总分只有第三，但是&lt;code&gt;171&lt;/code&gt;和&lt;code&gt;d/2&lt;/code&gt;连续出现，说明它的reflection和怀疑倾向可能不是偶然。&lt;/strong&gt; 所以stage3没有继续加题，而是直接换岗位，让muse去重新评价和攻击这一轮的答案。&lt;/p&gt;
&lt;h3&gt;stage3：让muse当evaluator，再让sol审理它的攻击&lt;/h3&gt;
&lt;p&gt;| model / role     | sol在stage2的评分 | muse重新评分 | stage3中的额外数据                                                               |
| ---------------- | ----------------: | -----------: | -------------------------------------------------------------------------------- |
| gpt-5.6-sol      |                20 |           18 | 总排名仍然第一；负责meta-review，对Q4 critic报告判&lt;code&gt;OK with notes&lt;/code&gt;，对Q5判&lt;code&gt;BLOCK&lt;/code&gt; |
| gemini-3.8-flash |                12 |           12 | 总排名第二，局部题目顺序有变化                                                   |
| muse-spark-1.3   |                11 |           11 | 总排名第三；critic中约三成完全成立、三成部分成立，硬误报约二到三成               |
| glm-5.3          |                 8 |            9 | 总排名第四，但muse对它的局部判断与sol并不完全一样                                |&lt;/p&gt;
&lt;p&gt;muse作为传统evaluator时，最后的总排名和sol完全一致，但是五题中有四题的局部顺序发生了变化，而且Q1出现了明显的自评跳变。把它改成只攻击具体claim以后，它确实找到了sol第一轮漏掉的问题，但误报也很集中：很多时候都是没有先&lt;code&gt;ls&lt;/code&gt;、没有先算完、没有检查完整轨道，就提前宣布对方错了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;所以最后的结论不是“muse适合当最终裁判”，而是它很适合产生高价值的怀疑；这些怀疑再交给sol做独立审理。&lt;/strong&gt; 也就是相当于再我们的产生idea阶段的gemini的角色，一个聪明但是执行力以及判断力都不太行的小笨蛋，这个是我们的muse应该充当的一个角色&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/image-20260905010900982.png&quot; alt=&quot;Herdr + Pi 工作台&quot;&gt;&lt;/p&gt;
&lt;p&gt;附上一个工作台(herdr+pi的图片)&lt;/p&gt;</content:encoded><h:img src="/_astro/Reze6.BACsjmu4.webp"/><enclosure url="/_astro/Reze6.BACsjmu4.webp"/></item><item><title>My Paper-reading methodology</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/my-paper-reading-methodology/my-paper-reading-methodology</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/my-paper-reading-methodology/my-paper-reading-methodology</guid><description>在 AI 时代重构论文阅读方法论：按论文来源与目标将阅读分为“有趣论文、领域相关、研究逻辑型、神作”四类，分别配置 prompt、交付物与阅读深度，试运行两周后修正。</description><pubDate>Thu, 06 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;为什么要写这篇呢，因为随着ai地发展，论文阅读，好像变得没有那么那么重要了，虽然也有很多地老师讲，一些常见地论文阅读方法，比如第一遍，第二遍，第三遍阅读，但是个人感觉，阅读几遍再目前已经不是最关键的了，而是那些地方是你&lt;strong&gt;直接去读&lt;/strong&gt;，那些地方是你 &lt;strong&gt;用ai辅助阅读&lt;/strong&gt;，因此论文阅读流也不能仅仅分成 ai总结大意，以及从头到尾精读这两种，还需要有更加精细化的分类&lt;/p&gt;
&lt;h2&gt;论文阅读流&lt;/h2&gt;
&lt;p&gt;初步分成了几类，考虑到我们平时涉及到的论文有几种(1)比如再公众号或者xhs上面看到的有趣的论文，(2)你自己的领域的，偶然刷到的 (3) 老师或者别人分享给你的，需要理清作者思路，insight的论文 (4)绝世神作 对于这几种，目前我的大概解决方法是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A1: 有趣的论文&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;场景：公众号/xhs&lt;/li&gt;
&lt;li&gt;prompt: &lt;code&gt;阅读这篇论文，告诉我其核心methodology，并概括其insight&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;交付结果: 一个 ChatGPT 对话链接,一句话概括核心 insight。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A2:自己领域里的普通相关论文&lt;/strong&gt;
基于不同的场景，可能你的领域更加偏重于method本身，可能你的领域偏向于task/metrics本身的设计，实验是怎么设计的，因此我们的这种场景下的prompt需要注重:
&lt;strong&gt;研究的问题是什么，insight是什么，method,核心实验的tasks/metrics设计，有那些探索性实验，作者承认的limitation以及gpt觉得的limitation&lt;/strong&gt;，因此我们的设计大概是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prompt:依据自己的领域，去进行设计&lt;/li&gt;
&lt;li&gt;交付结果：同上，gpt对话链接+insight+你想要了解的，核心的设计&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;B类：研究逻辑型&lt;/strong&gt;
需要去理清逻辑的，需要学会更着作者走的那种paper,比如像老师给我的paper
step1:纯看论文的abstract以及introduction,目的是了解这个问题提出来的背景，以及之前的方法做了什么，该paper的核心insight
step2:比如method,experiments,先让ai去读，让我有个大概的概念，然后再去对于其细节，进行深挖，尤其是有意思的experiment设计，以及作者对于特殊现象的analysis&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;交付结果：abstract+introduction的笔记+对于method/experiments部分得，大概理解&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;C类：神作&lt;/strong&gt;
无需多言，基本上都写得非常好，比如deepseek v3 technical report,还有像rlhf,建议好好阅读
交付结果&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你读得时候记录得全文笔记&lt;/li&gt;
&lt;li&gt;自己理解下，回答A2中得一系列得问题+自己得一些心得体会&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前的大概工作流就是这样，试运行大概2周时间，等到到时候，再去进行进一步的修正。&lt;/p&gt;</content:encoded><h:img src="/_astro/titan2.ekMw1O7C.jpg"/><enclosure url="/_astro/titan2.ekMw1O7C.jpg"/></item><item><title>工作流反思（二）</title><link>https://bauklotze.vercel.app/blog/reflections/%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%8F%8D%E6%80%9D%E4%BA%8C/%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%8F%8D%E6%80%9D%E4%BA%8C</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%8F%8D%E6%80%9D%E4%BA%8C/%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%8F%8D%E6%80%9D%E4%BA%8C</guid><description>暑期过半，对近一个月的工作流做系统总结：规划每日有效工作时长，区分科研、学习与沟通任务的时间/精力成本，并尝试用流式管理和每日记录来持续优化节奏。</description><pubDate>Fri, 24 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;暑期过半了吧，在大概7月初地时候，是一个初步地思考，而现在，已经一个月快过去了，虽然还有一周，但是这3周呢，我做了很多东西吗，做了，但是又好像没有做什么东西，不过也是时候来好好地总结一下过去地这一个月地工作流&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工作时长规划&lt;/strong&gt;
对于第一点，也就是我平时到底生活可以怎么去，什么时关于时间的一个问题，首先我平时可以做到的是早上8点半去到图书馆，当然这是在我平时大概每天在一点半左右睡觉的情况下，但是现在有一个很大的问题，就是说晚上一点半睡觉&lt;/p&gt;
&lt;p&gt;如果话再说回来的话，实际上就是从早上的8点半一直到中午的12点多，然后从下午的，因为中午还需要吃饭，所以说也是总共是一个小时的休息时间，或者稍微放宽一点，就是一个半小时，最好还是一个小时内解决，因此差不多至少从下午的一点半一直到下午的5点半四个小时，然后在最后是晚上的从7点半一直到11.3个半小时的时间，所以说是至少可以做到11个小时，所以说以后也要在平时的生活中要保证这样的一个有效的工作时长
以上是第一点，也就是工作地时长，然后在此基础上，可以有大概30min左右地一个空余，这样可以保证一个基本地作息和我地精力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工作流&lt;/strong&gt;
然后总的来说目前地工作流包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;科研流
&lt;ul&gt;
&lt;li&gt;自学课程&lt;/li&gt;
&lt;li&gt;完成任务类型，包括为了某一课题/目标地工作，这个是科研流&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;学习流
&lt;ul&gt;
&lt;li&gt;固定学习日程: 包括背单词，每天固定背诵15页单词&lt;/li&gt;
&lt;li&gt;以及其余：比如平时地时候地作业，或者像日常地讲座和听课&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;其余流： 主要包括和别人地沟通，还有像
普遍来说也就是以上地几个任务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而对于每一类地任务，所需要地专注度是不一样地，自己感觉有两个，一个是时间成本，还有一个是精力成本，时间成本分成你能不能分出来30%地东西给别的，而精力成本是你做这件事情，是否会极其消耗你地精力，因此对于以上地花&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;科研流
&lt;ul&gt;
&lt;li&gt;自学课程：时间成本+1，精力成本+1&lt;/li&gt;
&lt;li&gt;科研：时间成本+1，精力成本-2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;学习流：
&lt;ul&gt;
&lt;li&gt;固定学习：时间成本+1，精力成本-1&lt;/li&gt;
&lt;li&gt;其余：时间成本+0.5，精力成本-1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;其余流：时间成本+1，精力成本-1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果这样看地花，之后就可以更具这个，去看看目前地上限精力以及时间成本可以达到多少，目前初步地估算，我们地每天10.5地工作时长，理论上可以达到7个单位地时间成本，因此未来可以以此，去估算自己地精力地上限，并由此去看自己生活地别的方面成本如何&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流式管理&lt;/strong&gt;
https://zhuanlan.zhihu.com/p/2006174732488298539#:~:text=2024%E5%B9%B4,%E6%B4%BB%E5%87%BD%E6%95%B0%E2%80%9D%E3%80%82
然后就是以后我也会这么做，也就是俗称地流式管理
1.5h实际上是一个挺不错地时间片段，到时间之后，大概花10min总结大概做了些什么东西，做好上下地接口，并且进行相应地记录，通过这种方式，我们可以成功地将我们地整个生活给进行非常合理地划分。
说到休息，可能之前也确实没有意识到这个，之前就是中午和晚上已经做了比较严格地规定，也就是休息时间包括吃饭1h,然后晚上地休息是1.5h,最后睡觉前，晚上回到宿舍之后，是1h地休息时间，只有这样，进行如此地管理，才可以有更好地学习效率。
以上地这个，大概是这样地，也是目前对于自己地生活状态地一个总结还有准备提高地东西。也是需要进一步地提高吧。之后也会去进一步地调整，看看自己是否还有可以进一步地去改进和调整地东西。比如自己平时地生活到底需要我花多少地时间以及我地精力成本去进行维护。&lt;/p&gt;
&lt;p&gt;接下来将会每天进行相应地每天做了什么东西地记录以及输出。并且进行记录，这一天做了什么，之后也会开一个专栏吧&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.ainunBWr.webp"/><enclosure url="/_astro/titan4.ainunBWr.webp"/></item><item><title>26Spring总结</title><link>https://bauklotze.vercel.app/blog/reflections/26spring%E6%80%BB%E7%BB%93/26spring%E6%80%BB%E7%BB%93</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/26spring%E6%80%BB%E7%BB%93/26spring%E6%80%BB%E7%BB%93</guid><description>大二下学期总结与暑假计划：科研入门、工作流变革、方向思考，以及生活的锚点</description><pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;6.30号，在经过了一周速通完一个学期的6 门课程后，这个忙到爆炸的学期也算是终于告一段落了。&lt;/p&gt;
&lt;p&gt;这一个学期里面，为什么一点点的文章都没有写呢，一方面是确实，由于科研和一大堆地事务，没有时间去进行自学，课内地东西，只有到了期末的时候，才会去仔细地学习。所以这个学期没有怎么写东西。之后页会尽快补上来吧。另一个方面。可能科研上，工作流变化太快了吧，天天的vibe code,token消耗量几千上亿的，但是感觉都是被时代，被任务推着往前走，也就是所谓地被时代裹挟着往前走地感觉。只是没有思考以及输出，也就无法像伊雷娜那样，进一步地完善自己地工作流，你也只能是匀速运动，而不是加速运动，&lt;strong&gt;加速度&lt;/strong&gt;，我觉得才是再当今地ai时代最重要地东西&lt;/p&gt;
&lt;p&gt;现在回望过去地一个学期，虽然知识没有学太多，但是思考问题地方式，关于我想要做什么，成为什么样地人，优点以及缺点都算有了更深地体会。&lt;/p&gt;
&lt;h2&gt;科研以及课程上&lt;/h2&gt;
&lt;p&gt;这个学期虽然好像没有做多少事情，回过头来看，又好像做了很多的事情。&lt;/p&gt;
&lt;p&gt;1.关于师兄给的方向，进行了大量的探索以及研究。不下于大量的实验(当然都失败了)，也在这个过程中成功的将vibe coding给融入了我的工作流当中&lt;/p&gt;
&lt;p&gt;1.关于科研入门：上个学期进了实验室，也开始了关于推荐系统地相关研究，从什么也不会，到逐步掌握代码框架，会开始设计实验，验证猜想，并且和别人进行汇报，虽然暂时没有产出，但是至少科研地基本流程打通了。&lt;/p&gt;
&lt;p&gt;2.一段小插曲：3-5月份，也和几个同学，一起就agent-memory方面进行了一些研究，不同于之前师兄给方向，而是自己去进行探索，查找问题，实验，迭代，paper写作，也体验了什么叫连续一周晚上4-5点睡觉。总的来说，&lt;/p&gt;
&lt;p&gt;3.比赛方面：打了一场黑客松，agent recommendation到底怎么做，陪伴？这些都是非常有意思地问题，也明白了，到底ai产品端是做什么，虽然内心持有鄙夷态度，但是也再这个过程中思考了，自己到底想要做些什么东西。&lt;/p&gt;
&lt;p&gt;4.课程上，包括深度学习基础开始初步地了解一些些量化交易地东西(同花顺就是一坨shi),以及像计算方法，量子物理这种，有意思地课程，对于这些课程，现在也有了自己，从开始学一门课程，到如何掌握，如何得到高分地一套工作流。&lt;/p&gt;
&lt;p&gt;5.和别人地沟通能力，包括联系老师，包括和前沿专家地相关了解，实习，暑研，有了产出之后，reach out 如何和别人沟通，如何将自己的想法更好的表达出去，这个是非常的重要的。&lt;/p&gt;
&lt;p&gt;总的来说呢，虽然这个学期，没有推进过多的自学的内容(这个确实不应该)，但是也确实有了一套初步的，自己对于ai如何使用，科研怎么做问题&amp;#x26;&amp;#x26;实验&amp;#x26;&amp;#x26;调研，这种东西的思考，也初步的感知到了自己想要做什么东西，那种&lt;strong&gt;可解释的，一个复杂的pattern中出现的，可泛化地规律&lt;/strong&gt;，之后也会专门出一篇文章来好好讲讲这个&lt;/p&gt;
&lt;h2&gt;我到底想要做什么&lt;/h2&gt;
&lt;p&gt;可能这个学期提升的是一些软实力吧，不一定是那种明确的成果，学了多少课什么的，虽然这个也非常重要，但是有更多的问题需要思考，包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我想要做出来什么样的东西，是做出来一大堆的垃圾，还是那种10年后还有人能看见，能记住的东西呢&lt;/li&gt;
&lt;li&gt;我到底应该in 那个方向？就我个人而言，vlm,具身，多模态，agent都非常有意思，但是我自己的感觉，这些都是偏向于llm的应用端的，能给人提供便利，好玩，也有非常多的金子可以挖，但是自己还是更加偏向于去研究一些，llm内部的机理，无论是从这种机理去思考别的问题，还是直接去研究这种东西，至少我感觉，当前的llm黑盒的背后，是绝对有我们没有发现的那种深层次的逻辑的&lt;/li&gt;
&lt;li&gt;未来想要怎么走呢？实习，暑研，读研读博phd,教职/大厂，都是需要思考的问题。&lt;/li&gt;
&lt;li&gt;未来想要什么样的生活呢？不求大富大贵，只是活着，有一些小小的盼头，能做一些自己感兴趣的研究，平淡的生活，反而可能是我最渴望的。&lt;/li&gt;
&lt;li&gt;最后就是关于agi时代，到底是什么呢，目前还没有一个明确的答复，但是也确实是时候，来稍微的静下心来，看看到底ai发展到了什么地步了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;思路很乱，很多，但是也算是从上个学期结束，啥也不知道地状态，现在也算是对以上问题有了一些自己地答案。&lt;/p&gt;
&lt;h3&gt;暑假任务&lt;/h3&gt;
&lt;p&gt;暑期的话，有非常多的任务需要去做&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;科研上: 可解释性&amp;#x26;&amp;#x26;推荐系统的相关研究，尽量抽出时间，尽可能地推进，以及思考.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;学习上: 有非常多地需要去学地东西，因为越来越发现，你地insight，你地切入点，你能理解一篇paper地什么程度，真的取决于你地内在，&lt;strong&gt;你了解过多少东西&lt;/strong&gt;，你能不能想到，原来可以这么去想，妙哉妙哉，这个是非常重要地。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Information Theory by MacKay：上个学期余下来地课程，看完这个之后，之后关于信息地流动，空间，应该有更多地理解。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cs336: 手搓llm模型，每一个部件，根据karpathy地话，只有你真正地搓过每一个部件，才是理解了这个东西&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cs224系列，包括:cs224w(GNN),cs224U(自然语言理解)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CS234：RL后训练，目前无论是grpo还是什么的，都存在大大小小的问题，因此从前人的智慧中找到灵感，不失为好的选择&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cs231n: 虽然以后不会专门去做多模态，但是llm在我地理解中，语言本身就不是那么好地载体，因此不能局限于语言模型。因此cs231n非常有必要去学&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CS228：想要去学&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同时，9月要考gre,因此单词，阅读等等，目标330+&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;more about me&lt;/h3&gt;
&lt;p&gt;这个学期，当然，看了非常多的番以及入坑了一大堆的游戏，包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;东京喰种，咒术回战，在超市后门吸烟的二人，你的名字等等，可能逐渐的逐渐的，我开始从只看王道热血番，逐渐逐渐的开始看像你的名字这种情感更为细腻的番了吧，成熟了？？还是什么呢，我也不知道。&lt;/li&gt;
&lt;li&gt;土豆兄弟，black jack, mc稍微玩了一会会，以及双人成行，中国式家长，celeste等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只能说，当自己的xhs以及bilibili上越来越多都是各种ai信息之后，确实需要找到更多的生活上的锚点。包括但是不限于飞盘，篮球，羽毛球，滑冰。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;19岁，到底是什么样的一年，朝气？不知道，感觉自己现在更像佐佐木，成熟？？又不是。只知道，目前还处于一个生活急速变动地阶段，确实需要抓住这个精力最旺盛(红豆泥？？)地时候，变更自己地工作流，并且严格地执行。也算是个契机吧&lt;/p&gt;
&lt;p&gt;至少我的18岁这一年，收获还是蛮大的，希望可以成功的将以上的任务完成吧。&lt;/p&gt;</content:encoded><h:img src="/_astro/titan5.wO205hmW.jpg"/><enclosure url="/_astro/titan5.wO205hmW.jpg"/></item><item><title>我的音乐歌单</title><link>https://bauklotze.vercel.app/blog/daily-life/my-music</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/daily-life/my-music</guid><description>My Music</description><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;../../../background/titan4.jpg
&lt;strong&gt;动漫歌曲&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;进击的巨人: op&amp;#x26;ed,所有的bgm，甚至经典的场面(玛丽亚之墙夺回战，兵长的一些曲目)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;鬼灭之刃：op，义勇，蝴蝶忍，炭治郎，时透的主题曲，以及无限城的各种插曲(以通透世界为代表)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JoJo: 主要从3-6的所有的op,以及animenz的曲目&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;电锯人: 所有op, jane doe,以及in the pool, sweet dreams等神曲&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;死亡笔记全部op&amp;#x26;&amp;#x26;部分的插曲&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unravel,声嘶力竭&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;东京喰种的所有op/ed,以及向glassy sky这样的曲子&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;四月是你的谎言op&amp;#x26;ed,某科学的超能电磁炮op&amp;#x26;ed，你的名字全部op&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;海贼王全部op以及部分ed, 灌篮高手曲目&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;别的曲目&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;游戏中的:空洞骑士&amp;#x26;&amp;#x26;丝之歌&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;animenz的全部好听的钢琴曲&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宫崎骏的经典电影中的插曲(还没有特别整理过)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;美丽的钢琴曲(如花之舞)，以及一些合唱&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;电影中的曲目:哈利波特，that girl,三傻大闹宝莱坞(如give me some sunshine等)，迪士尼电影(疯狂动物城1，2，冰雪奇缘等)中的一些曲子。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;未完待续...&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果大家还有什么好听的曲子也可以推荐给我！！&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>openclaw部署</title><link>https://bauklotze.vercel.app/blog/technical/openclaw-basic</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/technical/openclaw-basic</guid><description>openclaw</description><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;ol&gt;
&lt;li&gt;skill-1: 配置了一个github-monitor 工具：
自定义了一个脚本，从而直接在对话框中输入:使用github-monitor监控github3天内的用户信息，包括stars, commit等，然后就会自动调用工具去实现功能&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;GITHUB_TOKEN=...&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;skill-2: 网页搜索工具,使用tavily-api
TAVILY_API_KEY=...&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;==openclaw部署中的东西==&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-linux&quot;&gt;# 更新node.js
 nvm install --lts
wesle@fwh:~$ openclaw channels add 添加channels
wesle@fwh:~$ openclaw pairing list telegram 进行和telegram bot的链接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;https://zhuanlan.zhihu.com/p/2002522071650018395  添加deepseek api&lt;/p&gt;
&lt;p&gt;==openclaw init==&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新node.js&lt;/li&gt;
&lt;li&gt;模型api配置: z.ai,默认使用的是zai/glm-4.5-air,以及deepseek模型(通过修改settings.json文件)
deepseek:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&quot;providers&quot;: {
  &quot;zai&quot;: { ... }, // 保留你原来的 GLM 配置
  &quot;deepseek&quot;: {
    &quot;baseUrl&quot;: &quot;https://api.deepseek.com/v1&quot;,
    &quot;api&quot;: &quot;deepseek-api&quot;,
    &quot;models&quot;: [
      {
        &quot;id&quot;: &quot;deepseek-chat&quot;,
        &quot;name&quot;: &quot;DeepSeek V3.2-chat&quot;,
        &quot;reasoning&quot;: false,
        &quot;input&quot;: [&quot;text&quot;],
        &quot;contextWindow&quot;: 65536,
        &quot;maxTokens&quot;: 4096
      },
      {
        &quot;id&quot;: &quot;deepseek-reasoner&quot;,
        &quot;name&quot;: &quot;DeepSeek V3.2-reason&quot;,
        &quot;reasoning&quot;: true,
        &quot;input&quot;: [&quot;text&quot;],
        &quot;contextWindow&quot;: 65536,
        &quot;maxTokens&quot;: 4096
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;channel: telegram personal bot配置&lt;/li&gt;
&lt;li&gt;openclaw启动:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;openclaw gateway
openclaw dashboard # 配置的密钥，共享密钥
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用了token校验机制，也就是对称密钥&lt;/p&gt;
&lt;p&gt;==Telegram bot api==:&lt;/p&gt;
&lt;p&gt;==Username==:
wesleyfei_personal_bot
==name==:
韩吉&lt;/p&gt;</content:encoded><h:img src="/_astro/cz2.CwLbkrqC.webp"/><enclosure url="/_astro/cz2.CwLbkrqC.webp"/></item><item><title>骑士比赛</title><link>https://bauklotze.vercel.app/blog/daily-life/cavaliers-games/cavaliers-games</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/daily-life/cavaliers-games/cavaliers-games</guid><description>Cavaliers Games</description><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;2.28 活塞vs骑士&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./images/Cavaliers-game_2026-02-28-02.png&quot; alt=&quot;&quot;&gt;
今天总体而言打的还是挺焦灼的，比赛直到最后一刻才分出来胜负，哨子非常黑。但是骑士在缺少哈基米组合下仍然由非常不俗的实力&lt;/p&gt;
&lt;p&gt;总结而言，防守在没有阿伦之后略有吃力，莫布里只能打中锋，锋线的防守非常吃力。我的建议是在面对活塞这种更靠内线的时候，尽量上双塔，莫布里作为外线的扫荡，从而内线的中锋去肉搏，解放莫布里。在进攻方面，小黑还是大心脏，但是太独，应该当成吉诺比利去用，作为乱战，作为终结点去使用。持球点还是要换成别人，莫布里，波特，未来的艾利斯都可以。&lt;/p&gt;
&lt;p&gt;总之，今天骑士缺少了3个持球点，仍然和活塞打到了最后时刻，希望哈基米组合早日康复，进一步磨合球队，总冠军还是非常有希望的。&lt;/p&gt;
&lt;h2&gt;2.12 骑士vs奇才&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;./images/Cavaliers-game_2026-02-12-26.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;今天早上一起来，骑士第一节就领先了16分，然后就没有看了。哈登本场表现不佳，1/4，25%命中率，送出10+助攻，末节惨遭DNP，最后轻松取胜(宠登蜜又宠登黑)。
最后不得不说阿特金森地执教水平是真的高呀，而且我们地&lt;strong&gt;哈基米组合水平是真的高呀&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;2.10 掘金vs骑士&lt;/h2&gt;
&lt;p&gt;拿下拿下，正义必胜！！！
首先今天确实哨太黑偏了，感觉约基奇都要和亚历山大坐一桌了，骑士被领先了一整场，好多次要气势时，被哨子吹下去了。不过还好，最后，审判之投，哈登打进关键3分，米切尔罚球准绝杀，总之，&lt;strong&gt;哈基米组合万岁&lt;/strong&gt;！！！
&lt;img src=&quot;./images/Cavaliers-game_2026-02-10-26.png&quot; alt=&quot;&quot;&gt;
从技术上来看，哈登现在可以将更多的体能分配到防守端了，今天直接4盖帽。不得不说在快船将哈登的防守练出来了，在骑士，空间更好，没有那么多的包夹，因此哈登可以在场上进攻的时候摸鱼，防守端可以分配更多的体力。
对于更多的分析内容，等到骑士队的阵容齐整之后再弄吧，因为毕竟防守体系在没有莫布里的时候完全是另一个样子。&lt;/p&gt;
&lt;h2&gt;2.8 国王vs骑士&lt;/h2&gt;
&lt;p&gt;今天哈登骑士首秀，先看数据
&lt;img src=&quot;images/Cavaliers-game_2026-02-08-28.png&quot; alt=&quot;&quot;&gt;
哈登今天表现还行，虽然上半场总共投篮8/2，三分5/2但是下半场手感回暖，末节狂砍15分，加上米切尔发力，下半场爆砍20+，尽管国王手感尤其出色，但是最后哈基米组合还是联手收割比赛。
从这场比赛中可以看出一些问题。骑士队，由于莫布里伤缺，整个骑士的&lt;strong&gt;防守&lt;/strong&gt;体系需要重新构建，因此&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;外线:米切尔(臂展，力量，可以进行1/2号位的防守)，泰森(不错的防守潜力)/替补:艾利斯，小黑(非常优秀的防守资源)&lt;/li&gt;
&lt;li&gt;锋线:哈登外线/防守小前/大前(力量优势), 别的球员得防守表现别的还需&lt;strong&gt;观察&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;内线:莫布里+阿伦
替补席上至少几个人都有合格的替补，无论是替补中锋还是控卫，唯一缺少的就是锋线替补(尤其是防守!!!)，等到骑士队整容齐整的比赛再看吧&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;哈登还需要适应节奏，以及哈基米之间的沟通，同时哈登持球以及球权分配怎么弄
决胜时刻，本质工作:喂饼+三分，&lt;/p&gt;</content:encoded><h:img src="/_astro/background.CrV3Jinz.jpg"/><enclosure url="/_astro/background.CrV3Jinz.jpg"/></item><item><title>CS146S Week1: prompt engineering</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week1/prompt%E5%B7%A5%E7%A8%8B</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week1/prompt%E5%B7%A5%E7%A8%8B</guid><description>prompt engineering</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS146s week1的课程以及assignment是介绍并且练习了prompt工程中的小技巧，下面来进行一些梳理。&lt;/p&gt;
&lt;h2&gt;Basic knowledge&lt;/h2&gt;
&lt;p&gt;prompt就和language一样，而随着参数量的增加，LLM中涌现出来一系列的能力, 以及一些可以增强模型性能的小trick。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;zero shot learning: 仅仅输入指令，即使模型在pre-train以及sft阶段没有见过这些任务，仍然会有非常不错的表现(=&gt; 这也是为什么LLM可以理解我们奇奇怪怪的要求的原因)&lt;/li&gt;
&lt;li&gt;few-shot learning: 我们想要模型完成一个tasks,但是通过在prompt中增加examples,从而模型可以提取到解决问题的方法。 GPT-2paper中，告诉我们LLM可以由此大大提升模型的性能
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-14.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;li&gt;Chain of thought: 通过在prompt中让模型进行思考/分步的思考，在CoT的原paper中，发现这大大增加模型思考的逻辑性以及最后的正确率。而实际操作中具体有
&lt;ul&gt;
&lt;li&gt;zero-cot(easy但是有效): prompt中增加&lt;strong&gt;think step by step&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;multi-cot: 添加若干个问题+解决问题的思考步骤
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-20.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Self-consistency: 个人理解这也是test-time scaling的一种，LLM虽然每一次可能答案不同，但是输出10，100次之后，答案会基本收敛，而且这个收敛结果正确性会更高，这就告诉我们，询问LLM的时候&lt;strong&gt;可以让其多输出几遍&lt;/strong&gt;增加正确率&lt;/li&gt;
&lt;li&gt;别的常见的trick:tool-use(引导模型使用工具),引导模型自我批判(reflect on your self)&lt;/li&gt;
&lt;li&gt;系统提示词：通过全局的规定来划定LLM的行为范围&amp;#x26;&amp;#x26;样式，而role pronpting会非常有效果
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-26.png&quot; alt=&quot;&quot;&gt;
prompt engineering是一门艺术，可以使用一些prompt优化工具，而更多的prompt设计技巧可以参考一些优秀样例以及&lt;a href=&quot;https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/prompt-improver&quot;&gt;anthropic的官方文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Assignment实践&lt;/h2&gt;
&lt;p&gt;week1的assignment设计非常巧妙，主要是让你设计若干提示词，使用这几种方法(&lt;code&gt;k-shot&lt;/code&gt;, &lt;code&gt;CoT&lt;/code&gt;, &lt;code&gt;Self-consistency&lt;/code&gt;, &lt;code&gt;RAG&lt;/code&gt;, &lt;code&gt;Tool-using&lt;/code&gt;, &lt;code&gt;Reflexion&lt;/code&gt;)从而达到一定的效果&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tasks1&lt;/strong&gt;: 设计一段system prompt, 从而用户输入“翻转以下单词：httpstatus”后，可以实现这个翻转的任务&lt;/p&gt;
&lt;p&gt;这个任务看上去非常easy,但是对于prompt的设计非常的看操作。即使反复修改prompt之后，成功率大概有40%。
最后的发现:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果要教会模型一些东西，需要更多的包含&lt;strong&gt;子模块&lt;/strong&gt;的example，而且需要更多的sub-example才可以教会(&gt;1)&lt;/li&gt;
&lt;li&gt;不要添加过多的cot,那只会搅乱&lt;/li&gt;
&lt;li&gt;不要加入过多的和子问题太相似的东西，加入一些比较robust的东西反而是更好的决定&lt;/li&gt;
&lt;li&gt;我们的指令的主题要是&lt;strong&gt;examples&lt;/strong&gt;，不要放太多太多的rules反而添乱，简洁清晰
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-36.png&quot; alt=&quot;&quot;&gt;
&lt;strong&gt;tasks2&lt;/strong&gt;: 使用cot,从而可以计算user prompt:&quot;calculate 3^(12345) mod 100&quot;
reflection:直接使用think step by step就可以激发模型的能力，而&lt;strong&gt;添加role playing prmpt&lt;/strong&gt;也是非常好的选择
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-40.png&quot; alt=&quot;&quot;&gt;
&lt;strong&gt;tasks3&lt;/strong&gt;:设计一个问题，解决一个应用题，并且验证self-consistency的正确性
reflection: 当问题easy的时候，就不需要困难的提示词，直接zero-shot就可以了
&lt;strong&gt;tasks4&lt;/strong&gt;:学习rag, 先生成一段代码，看能不能将补充的信息给填写进去
reflection:要强调简洁明了
&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-42.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;tasks5&lt;/strong&gt;:已有若干个工具，通过prompt教会模型如何辨别工具，以及使用工具的输入和输出
对于工具的声明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结构化工具的声明(列出所有工具，工具的参数，以及功能)，低temperature，声明json输出&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;You have access to tools. When asked to use a tool, respond with ONLY valid JSON.
TOOLS:
1. output_every_func_return_type: Analyzes a Python file and returns function names with their return types.
   - Parameter: file_path (string, optional)
FORMAT:
Always respond with valid JSON in this exact format:
{
  &quot;tool&quot;: &quot;&amp;#x3C;tool_name&gt;&quot;,
  &quot;args&quot;: {
    &quot;file_path&quot;: &quot;&quot;
  }
}
EXAMPLE:
User: Analyze the current file
Your response:
{
  &quot;tool&quot;: &quot;output_every_func_return_type&quot;,
  &quot;args&quot;: {
    &quot;file_path&quot;: &quot;&quot;
  }
}
RULES:
- Output ONLY JSON, no explanations
- The JSON must be valid
- Do not include any text outside the JSON object
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./prompt%E5%B7%A5%E7%A8%8B.assets/prompt%E5%B7%A5%E7%A8%8B_2026-02-16-45.png&quot; alt=&quot;&quot;&gt;
&lt;strong&gt;tasks6&lt;/strong&gt;: 一个“仿aget&quot;,可以进行代码的修正方法就是
&lt;strong&gt;Conclusion&lt;/strong&gt;:一般的提示词，需遵守
声明ai的身份(debugger, developer)
输入的东西(previous implementation，以及具体的failure)
我们希望最后的目标(从failure中理解为什么，并且修改代码，以及我们对于ai修改代码的限制，以及最后的输出的格式)&lt;/p&gt;
&lt;p&gt;以上就是cs146s中的prompt工程，虽然现在更多可以让gemini去写，但是只有了解了什么是好的，才能看懂以及更好的修改定制自己的prompt.&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>CS146S week2&amp;4-IDE(Copilot)&amp;&amp;Claude Code</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week24/cs146s-week24-idecopilotclaude-code</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week24/cs146s-week24-idecopilotclaude-code</guid><description>CS146S week2&amp;4-IDE(Copilot)&amp;&amp;Claude Code</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;cs146S对我而言最重要的，就是教会了我如何使用ai ide&amp;#x26;&amp;#x26;cli工具(copilot以及claude code), 并且提出了一系列principle,从而可以大大提高我们的工作效率，接下来我们来整理一下下吧！！！&lt;/p&gt;
&lt;h1&gt;Principle &amp;#x26;&amp;#x26; Ability&lt;/h1&gt;
&lt;p&gt;ai工具在逐步的演变中，从本地开发(copilot,cursor)，到协作云智能体(claud code)，未来可能会有更多的形式，但是有些principle和ability是需要现在开始培养的&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important principle&lt;/strong&gt;
基本的ai工具的响应可以分为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sync工具:20-1.5min的响应，让注意力集中在单一的任务上(快速迭代)&lt;/li&gt;
&lt;li&gt;async工具:10min-h级别的东西，人可以进行多个任务之间的切换注意力(可以运行多个agent,提高自己的并行能力)
&lt;strong&gt;principle&lt;/strong&gt;:减少semi-sync的状态，&lt;strong&gt;sync or async!!!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Important Ability&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;委派与多线程处理 (Delegation &amp;#x26; multi-threading)：&lt;/strong&gt; 学会同时管理多个并行任务 。这个能力非常非常的重要&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码阅读 (Code reading)：&lt;/strong&gt; 因为大部分代码由 AI 生成，人类需要快速阅读和审查代码 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规划与架构 (Planning, scoping, architecting)：&lt;/strong&gt; 定义问题和系统设计变得比写具体语法更重要 。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;AI IDE使用&lt;/h1&gt;
&lt;h2&gt;从 Inline Infilling 到全库 Context 检索&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础模式&lt;/strong&gt;:inline,function,single file,multi file(cursor,copilot之类的)
inline代码补全上下文为附近的代码，加上infilling llm
而chat/agent功能：代码作为embedding,并且检索project中的相关代码块&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ai-native&lt;/strong&gt;:后台代理，mcp,记忆学习，BugBot&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Act as a product manager&lt;/h2&gt;
&lt;p&gt;对于difficult tasks要学会像product manager一样去思考。直接将ai当成一个可以无限pua的员工，先规划好任务，然后给agent一份行动指南&lt;/p&gt;
&lt;p&gt;对于复杂任务，不要随意提问，要像一个产品一样，先去思考以下几个问题 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;目标 (Goal)&lt;/strong&gt;：变更的目的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定义 (Definitions)&lt;strong&gt;与&lt;/strong&gt;计划 (Plan)&lt;/strong&gt;：LLM 需要了解的前提条件、相关代码库部分、源文件变更计划。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试用例 (Test cases)&lt;/strong&gt;：如何测试、边缘情况处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;范围外 (Out-of-scope)&lt;/strong&gt;：哪些不应被修改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;扩展性 (Extensions)&lt;/strong&gt;：为未来设计预留空间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要有好的repo,最好提供一份关于repo的介绍README.md，包括&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- Repo orientation
- File structure
- Setup and environment
- Best practices
- Code style
- Access patterns
- APIs and contracts
- All of this should be thoroughly documented
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时配置好ai agent需要阅读的文档&lt;strong&gt;LLM 需要遵守的原则和规范&lt;/strong&gt;
比如&lt;code&gt;CLAUDE.md&lt;/code&gt; / &lt;code&gt;.cursorrules&lt;/code&gt; / &lt;code&gt;AGENTS.md&lt;/code&gt; / &lt;code&gt;llms.txt&lt;/code&gt;
以及AGENTS.md(对于agent的readme.md文件),可以参考一些specs
https://drive.google.com/file/d/1MZ0Qx68Vzw4x5x_XcV8XiPLp7fFDe1LJ/view&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;以上是大致的使用ai ide工具的流程，需要思考的问题以及原则。接下来则是具体到ai ide工具。&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;copilot使用&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;可以直接根据以上的原则，先交代任务，然后列plan，然后用agent模式一项项的去完成todo即可。在week2的assignment中，完成了一个&lt;strong&gt;自动提取todo list的东西&lt;/strong&gt;，详细请见github:https://github.com/wesleyfei1/Stanford-CS146S-WesleyFei/tree/main/week2&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Claude code使用&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;./CS146S%20week2&amp;#x26;4-IDE(Copilot)&amp;#x26;&amp;#x26;Claude%20Code.assets/CS146S%20week2&amp;#x26;4-IDE(Copilot)&amp;#x26;&amp;#x26;Claude%20Code_2026-02-16-18.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;安装&lt;/strong&gt;:对于安装(wsl以及claude code)的话就不细讲了，详细可见 https://axi404.top/blog/wsl-coding 这里有详细的介绍&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;api配置&lt;/strong&gt;: 显然直接使用claude的模型太贵了，所以接入第三方api就是非常好的选择。
在&lt;code&gt;~/.claude/settings.json&lt;/code&gt;中设置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;env&quot;: {
    &quot;ANTHROPIC_DEFAULT_HAIKU_MODEL&quot;: &quot;deepseek-chat&quot;,
    &quot;ANTHROPIC_DEFAULT_OPUS_MODEL&quot;: &quot;deepseek-reasoner&quot;,
    &quot;ANTHROPIC_DEFAULT_SONNET_MODEL&quot;: &quot;deepseek-reasoner&quot;,
    &quot;ANTHROPIC_MODEL&quot;: &quot;deepseek-chat&quot;,
    &quot;ANTHROPIC_REASONING_MODEL&quot;: &quot;deepseek-reasoner&quot;,
    &quot;ANTHROPIC_AUTH_TOKEN&quot;: &quot;你的api&quot;,
    &quot;ANTHROPIC_BASE_URL&quot;: &quot;https://api.deepseek.com/anthropic&quot;,
    &quot;API_TIMEOUT_MS&quot;: &quot;3000000&quot;,
    &quot;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&quot;: &quot;1&quot;
  },
  &quot;includeCoAuthoredBy&quot;: false,
  &quot;model&quot;: &quot;deepseek-chat&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里我选择的是deepseek的api,大家有什么&lt;strong&gt;便宜好用的plan/模型&lt;/strong&gt;可以在评论区留言推荐哈&lt;/p&gt;
&lt;p&gt;claude code的最大好处就是&lt;strong&gt;无论是工具，还是sub agent都非常容易配置，全部为md格式&lt;/strong&gt;，而且可以高度定制化。对于一个project,如果我们使用了/init命令后，在该project命令下可以进行配置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/project/CLAUDE.md: 制定了整体claude在该project下运行时&lt;strong&gt;遵从的行为准则，以及介绍项目大体的情况&lt;/strong&gt;，在书写时&lt;strong&gt;简洁清晰，明确的角色以及项目结构，设定好语气&lt;/strong&gt;，比如&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# Claude Project Guide
## Build &amp;#x26; Test Commands
- Install: `pnpm install`
- Build: `pnpm build`
- Test single file: `pnpm test &amp;#x3C;path_to_file&gt;`
- Full test suite: `pnpm test`
- Lint/Fix: `pnpm lint:fix`
## Coding Standards
- **Architecture**: Follow hexagonal architecture; keep logic in `/domain` and side effects in `/infrastructure`.
- **Types**: Always use strict TypeScript; interfaces are preferred over type aliases.
- **Naming**: Use PascalCase for components and camelCase for hooks.
- **Error Handling**: Use the `Result` pattern (success/failure objects) instead of throwing exceptions.
## Project Structure Highlights
- `/src/components`: UI-only shared components.
- `/src/hooks`: Custom React hooks for business logic.
- `/src/lib/api`: All Axios instances and API definitions.
## Important Context
- This project uses **Tailwind CSS** for styling; do not use CSS-in-JS.
- We use **Zustand** for state management (located in `/src/store`).
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;/project/.claude/settings.local.json: 设定在该project中claude code的权限&lt;/li&gt;
&lt;li&gt;/project/.claude/commands: 添加各种你想要设定的工具，比如我想要添加一个自动进行测试，书写tests以及修复的工具，直接增加一个&lt;code&gt;super-fix.md&lt;/code&gt;,从而直接使用**super-fix **触发&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# /super-fix
Automatically fix linting issues, format code, and run tests until they pass.
## Intent
Streamline the development loop by automating repetitive quality checks and iterative debugging.
## Steps
1. **Linting**: Run `make lint`. If it fails, analyze the ruff/black output and apply necessary fixes to the source code.
2. **Formatting**: Run `make format` to ensure the code adheres to the project&apos;s style guide.
3. **Testing**: Run `make test`.
4. **Iterative Debug**: If tests fail:
    - Capture the error message and traceback.
    - Analyze the relevant files in `backend/app/` to identify the bug.
    - Apply a fix and repeat from Step 1.
5. **Report**: Summarize the changes made and confirm the final status of the test suite.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;/project/.claude/agents: 当前的project中的一些子agent,可以手动设定，也可以根据claude自行制定agent,同样会以md格式存储。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;以上就是我在cs146s的week2&amp;#x26;4中得到的一些体会，copilot已经开始高强度使用了，但是claude code的使用还在初步的探索中，等到未来使用更加熟练后，应该会有不一样的体会。&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>CS146S week3-Modern Agent&amp;&amp;MCP介绍</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week3/cs146s-week3</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week3/cs146s-week3</guid><description>CS146S week3-Modern Agent&amp;&amp;MCP introduction</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;现代的agent肯定不只是对话，还会使用工具与现实世界进行交互，而交互&quot;协议”就是MCP，CS146s week3的课程以及assignment是介绍MCP的概念以及如何设计自己的MCP，下面来进行一些梳理。&lt;/p&gt;
&lt;h1&gt;Modern Agent&lt;/h1&gt;
&lt;h2&gt;Agent底层架构&lt;/h2&gt;
&lt;p&gt;用户与server交互时，会运行一个带有底层LLM的循环，在每一轮对话中，用户输入提示词，LLM发出工具调用，执行完工具后返回给LLM,最后将结果呈现给用户。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LLM输入包括:&lt;/strong&gt; System Prompt，User prompt,assistant prompt(模型过去的回答)
&lt;strong&gt;一般的流程为&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读取与对话管理&lt;/strong&gt;：从终端读取输入，并不断追加到对话历史中 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具声明&lt;/strong&gt;：告知 LLM 有哪些工具可用 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具调用请求&lt;/strong&gt;：LLM 在适当的时候请求使用工具 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具执行&lt;/strong&gt;：在离线状态下执行工具，并将结果返回给 LLM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显然，像上下文过长，遗忘等问题都是会出现的，因此可以考虑一些小tips&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前置context重置：将前面的内容总结成一个tiny prompt&lt;/li&gt;
&lt;li&gt;system reminder:适当的加入一些别的内容(prompt)来防止遗忘&lt;/li&gt;
&lt;li&gt;sub agent以及结构化的输出&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why MCP&lt;/h2&gt;
&lt;p&gt;MCP出现前LLM和各种工具的api调用非常混乱，需要M8n的配置，过于的麻烦。因此MCP是一种开放协议，类似于计算机网络中的协议，只要LLM有调用工具的需求，就发出&quot;query&quot;,而工具端在收到&quot;query&quot;之后做出应答，避免混乱。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心术语&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;Host (主机)：如 Cursor, Claude Desktop 。&lt;/li&gt;
&lt;li&gt;MCP Client (客户端)：嵌入在主机中的库，维持与服务器的有状态会话 。&lt;/li&gt;
&lt;li&gt;MCP Server (服务端)：工具前的轻量级封装 。&lt;/li&gt;
&lt;li&gt;Tool (工具)：可调用的函数（数据源或 API） 。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工作流程&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;客户端向 MCP 服务端请求工具列表 (&lt;code&gt;tools/list&lt;/code&gt;) 。&lt;/li&gt;
&lt;li&gt;服务端返回描述每个工具的 JSON（名称、摘要、JSON Schema） 。&lt;/li&gt;
&lt;li&gt;主机将 JSON 注入模型的上下文中 。&lt;/li&gt;
&lt;li&gt;用户提示触发模型，输出结构化的工具调用 。&lt;/li&gt;
&lt;li&gt;MCP 服务端执行操作，对话继续 。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输层&lt;/strong&gt;：MCP 提供 stdio(标准输入和输出) 和 SSE (Server-Sent Events，基于HTTP的更加长时的协议) 传输层 。
&lt;img src=&quot;./CS146S%20week3-Modern%20Agent&amp;#x26;&amp;#x26;MCP%E4%BB%8B%E7%BB%8D.assets/%E7%8E%B0%E4%BB%A3Agent%EF%BC%8CMCP%E8%AE%BE%E8%AE%A1%E4%B8%8E%E4%BD%BF%E7%94%A8_2026-02-16-09.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;An MCP example&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pathlib import Path
from typing import Any, Dict, List
from fastmcp import FastMCP

mcp = FastMCP(name=&quot;SimpleMCPTestServer&quot;)


def resolve_abs_path(path_str: str) -&gt; Path:
    &quot;&quot;&quot;
    file.py -&gt; /Users/home/mihail/modern-software-dev-lectures/file.py
    &quot;&quot;&quot;
    path = Path(path_str).expanduser()
    if not path.is_absolute():
        path = (Path.cwd() / path).resolve()
    return path

@mcp.tool
def read_file_tool(filename: str) -&gt; Dict[str, Any]:
    &quot;&quot;&quot;
    Gets the full content of a file provided by the user.
    :param filename: The name of the file to read.
    :return: The full content of the file.
    &quot;&quot;&quot;
    full_path = resolve_abs_path(filename)
    print(full_path)
    # TODO (mihail): Be more defensive in the file reading here
    with open(str(full_path), &quot;r&quot;) as f:
        content = f.read()
    return {
        &quot;file_path&quot;: str(full_path),
        &quot;content&quot;: content
    }

@mcp.tool
def list_files_tool(path: str) -&gt; Dict[str, Any]:
    &quot;&quot;&quot;
    Lists the files in a directory provided by the user.
    :param path: The path to the directory to list files from.
    :return: A list of files in the directory.
    &quot;&quot;&quot;
    full_path = resolve_abs_path(path)
    all_files = []
    for item in full_path.iterdir():
        all_files.append({
            &quot;filename&quot;: item.name,
            &quot;type&quot;: &quot;file&quot; if item.is_file() else &quot;dir&quot;
        })
    return {
        &quot;path&quot;: str(full_path),
        &quot;files&quot;: all_files
    }

@mcp.tool
def edit_file_tool(path: str, old_str: str, new_str: str) -&gt; Dict[str, Any]:
    &quot;&quot;&quot;
    Replaces first occurrence of old_str with new_str in file. If old_str is empty, creates/overwrites file with new_str.
    :param path: The path to the file to edit.
    :param old_str: The string to replace.
    :param new_str: The string to replace with.
    :return: A dictionary with the path to the file and the action taken.
    &quot;&quot;&quot;
    full_path = resolve_abs_path(path)
    p = Path(full_path)
    if old_str == &quot;&quot;:
        p.write_text(new_str, encoding=&quot;utf-8&quot;)
        return {
            &quot;path&quot;: str(full_path),
            &quot;action&quot;: &quot;created_file&quot;
        }
    original = p.read_text(encoding=&quot;utf-8&quot;)
    if original.find(old_str) == -1:
        return {
            &quot;path&quot;: str(full_path),
            &quot;action&quot;: &quot;old_str not found&quot;
        }
    edited = original.replace(old_str, new_str, 1)
    p.write_text(edited, encoding=&quot;utf-8&quot;)
    return {
        &quot;path&quot;: str(full_path),
        &quot;action&quot;: &quot;edited&quot;
    }

if __name__ == &quot;__main__&quot;:
    mcp.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如上一个程序的话
当你运行这段代码并将其集成到 Cursor 后，流程如下 ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;注册&lt;/strong&gt;: 客户端（如 Cursor）启动该脚本，调用 &lt;code&gt;tools/list&lt;/code&gt; 获取这三个工具的说明 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发&lt;/strong&gt;: 你对 AI 说：“帮我看看 &lt;code&gt;README.md&lt;/code&gt; 里写了什么。”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调用&lt;/strong&gt;: 模型识别出需要调用 &lt;code&gt;read_file_tool&lt;/code&gt;，并传入参数 &lt;code&gt;filename=&quot;README.md&quot;&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行&lt;/strong&gt;: 你的 Python 脚本运行 &lt;code&gt;read()&lt;/code&gt;，通过 stdio 将文件内容传回 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回复&lt;/strong&gt;: AI 读取到内容，在聊天框里为你总结&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Assignment Practice&lt;/h1&gt;
&lt;h2&gt;MCP设计&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Tasks requirement&lt;/strong&gt;: 要求设计一个MCP工具，在claude desktop中进行调用
&lt;strong&gt;构思&lt;/strong&gt;: 一个可以获取当天某一只股票信息的mcp,使用finnhub调股票信息
&lt;strong&gt;实现步骤&lt;/strong&gt;： copilot列计划，然后一条条实现，并且分别写unit test
&lt;code&gt;week3/server/&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;config.py: 加载.env并且进行查看是否会有报错，将.env中的东西转换成可以进行传输的&lt;/li&gt;
&lt;li&gt;finnhub_client.py: finnhub api封装，进行一堆的异常的处理,以及进行拉取网页信息和调用&lt;/li&gt;
&lt;li&gt;main.py:MCP服务器入口，将信息转换成stdio的格式，验证，请求，格式化，最后封装成一个个的工具&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体数据流程为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;用户（Claude Desktop）
  ↓ &quot;Get quote for AAPL&quot;
MCP 协议
  ↓ get_stock_quote(&quot;AAPL&quot;)
main.py
  ↓ _normalize_symbol → _build_client → client.get_quote
finnhub_client.py
  ↓ _request(&quot;quote&quot;, {&quot;symbol&quot;: &quot;AAPL&quot;})
Finnhub API
  ↓ 返回 {&quot;c&quot;: 123.45, &quot;d&quot;: 1.2, ...}
main.py
  ↓ _format_quote
Claude Desktop
  ← {&quot;status&quot;: &quot;ok&quot;, &quot;price&quot;: 123.45, ...}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Claude Desktop部署&lt;/h2&gt;
&lt;p&gt;设计好之后，部署到claude desktop。在&lt;code&gt;C:\Users\{username}\AppData\Roaming\Claude&lt;/code&gt;下的&lt;code&gt;claude_desktop_config.json中&lt;/code&gt;,添加这一段&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;mcpServers&quot;: {
    &quot;finnhub-stock&quot;: {
      &quot;command&quot;: &quot;D:\\conda_env\\envs\\cs146s\\python.exe&quot;, //因为我是在cs146s环境下使用
      &quot;args&quot;: [
        &quot;-m&quot;,
        &quot;week3.server.main&quot;
      ],
      &quot;env&quot;: {
        &quot;FINNHUB_API_KEY&quot;: &quot;your-api&quot;,
        &quot;PYTHONPATH&quot;: &quot;D:\\WesleyFei\\Alpha-lab\\0_Inbox\\modern-software-dev-assignments&quot;
      }
    }
  },
  &quot;preferences&quot;: {
    &quot;sidebarMode&quot;: &quot;chat&quot;,
    &quot;coworkScheduledTasksEnabled&quot;: false
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样你就能看到
&lt;img src=&quot;./CS146S%20week3-Modern%20Agent&amp;#x26;&amp;#x26;MCP%E4%BB%8B%E7%BB%8D.assets/%E7%8E%B0%E4%BB%A3Agent%EF%BC%8CMCP%E8%AE%BE%E8%AE%A1%E4%B8%8E%E4%BD%BF%E7%94%A8_2026-02-16-35.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;./CS146S%20week3-Modern%20Agent&amp;#x26;&amp;#x26;MCP%E4%BB%8B%E7%BB%8D.assets/%E7%8E%B0%E4%BB%A3Agent%EF%BC%8CMCP%E8%AE%BE%E8%AE%A1%E4%B8%8E%E4%BD%BF%E7%94%A8_2026-02-16-37.png&quot; alt=&quot;&quot;&gt;
具体程序参考我的github仓库 https://github.com/wesleyfei1/Stanford-CS146S-WesleyFei/tree/main/week3&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>CS146S week6-9 ai安全，审查，开发与维护</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week6-9/cs146s-week6-9-ai%E5%AE%89%E5%85%A8%E5%AE%A1%E6%9F%A5%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/26-2/cs146s-week6-9/cs146s-week6-9-ai%E5%AE%89%E5%85%A8%E5%AE%A1%E6%9F%A5%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4</guid><description>introducing the potential and harm of ai safety, checking, developing and ensuring</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;cs146s week6-9的内容比较宽泛，从安全防范到代码审查，再到应用开发的范式转变(课程上介绍了相应的warp,graphite,seeslope，bolt几个工具)，但是不可否认的是，ai正在改变整个软件生态&lt;/p&gt;
&lt;h1&gt;AI safety&lt;/h1&gt;
&lt;p&gt;传统的漏洞检测技术（如 SAST 分析应用程序安全、DAST 模拟攻击、SCA 分析外部依赖查找漏洞）在常规开发中已经非常成熟。然而，随着 AI 代理的引入，我们面临着全新的攻击。
现在的&lt;strong&gt;新的可能的attack&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI agent攻击&lt;/strong&gt;：prompt injection(指令导致ai偏离预期)，tool misuse(滥用集成的工具)，code attack(授权没有做好)
&lt;img src=&quot;./CS146S%20week6-9%20ai%E5%AE%89%E5%85%A8%EF%BC%8C%E5%AE%A1%E6%9F%A5%EF%BC%8C%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4.assets/CS146S%20week6_2026-02-15-10.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;./CS146S%20week6-9%20ai%E5%AE%89%E5%85%A8%EF%BC%8C%E5%AE%A1%E6%9F%A5%EF%BC%8C%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4.assets/CS146S%20week6_2026-02-15-10%201.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;![](./CS146S%20week6-9%20ai安全，审查，开发与维护.assets/CS146S%20week6_2026-02-15-10%202.png&lt;/p&gt;
&lt;p&gt;虽然 AI 使得自动化测试和安全测试的门槛大幅降低，变得更加容易，但当前的 AI 辅助工具依然存在明显的局限性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高误报率(AI SAST失败率极高)，非确定性分析(多次运行效果不同)，上下文腐烂(难以定位问题，而且不是所有的context是平等的)
&lt;strong&gt;未来展望：&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如何减少误报和幻觉，检测LLM生成的补丁有无问题，道德伦理问题(AI生成的补丁应该如何负责)，如何去验证呢&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;AI代码审查&lt;/h1&gt;
&lt;p&gt;代码审查是软件工程的生命线，缺乏严格审查的代码库最终都会演变成难以维护的“屎山”。&lt;/p&gt;
&lt;h2&gt;代码审查原则&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;审查的核心要素（按重要程度自下而上）：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;逻辑与正确性：例如严格区分和审查 &lt;code&gt;is&lt;/code&gt; 与== 的使用场景&lt;/li&gt;
&lt;li&gt;可读性与可维护性：代码编写需具有良好的分块与结构，便于人类阅读。&lt;/li&gt;
&lt;li&gt;性能优化：例如在查找操作中优先使用 &lt;code&gt;Set&lt;/code&gt; 以提升速度。&lt;/li&gt;
&lt;li&gt;安全性：严格避免使用任何带有潜在危险的代码模式。如下图
&lt;img src=&quot;./CS146S%20week6-9%20ai%E5%AE%89%E5%85%A8%EF%BC%8C%E5%AE%A1%E6%9F%A5%EF%BC%8C%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4.assets/CS146S%20week6&amp;#x26;7_2026-02-15-30.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;li&gt;使用最佳的实践
&lt;img src=&quot;./CS146S%20week6-9%20ai%E5%AE%89%E5%85%A8%EF%BC%8C%E5%AE%A1%E6%9F%A5%EF%BC%8C%E5%BC%80%E5%8F%91%E4%B8%8E%E7%BB%B4%E6%8A%A4.assets/CS146S%20week6&amp;#x26;7_2026-02-15-31.png&quot; alt=&quot;&quot;&gt;
从下到上越来越重要&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;AI in 代码审查&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;市场玩家&lt;/strong&gt;：目前市场上已经涌现出如 Graphite, Greptile, Coderabbit, Claude Code / Codex 等众多玩家。AI 的介入带来了审查效率的显著提升、开发者认知负荷的降低，并能够基于对代码库的整体理解实现持续改进。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 的能力边界&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI 能捕捉&lt;/strong&gt;：最佳实践、代码整洁度、文档、风格、边缘情况、性能问题、安全漏洞和 Bug。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 难以捕捉（目前）&lt;/strong&gt;：范围蔓延 (Scope Creep)、个人偏好 (Preference)、部落知识 (Tribal Knowledge) 以及意外的代码行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人机交互&lt;/strong&gt;：人类不希望从 LLM 那里接收关于风格的琐碎建议，也不希望把时间浪费在给 LLM 写这种建议上
目前技术上仍有局限（如难以捕捉特定的编码习惯或复杂的仓库逻辑），但我们可以通过提升&lt;strong&gt;外循环 (Outer loop)&lt;/strong&gt; （作者 -&gt; 测试 -&gt; 审查 -&gt; 合并 -&gt; 部署）中最大化ai的价值，但是要用到什么程度，就要看你的产品需求了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;AI APP 开发&lt;/h1&gt;
&lt;p&gt;现在开发一个应用越来越容易了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prompt即应用，工程师的角色扩展，门槛的降低
比如app builder architecture可以直接使用webcontainer以及prompt工程进行架构
&lt;strong&gt;新的隐患：&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;代码修复困难：由 AI 生成的庞大代码，一旦出现深层逻辑错误，人工介入修复的成本极高。&lt;/li&gt;
&lt;li&gt;复杂度天花板：纯 AI 生成的应用到底能支撑多高的业务复杂度仍是未知数。&lt;/li&gt;
&lt;li&gt;应用同质化与安全问题：模式化的生成容易导致产品千篇一律，且存在潜在的安全漏洞。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;未来的应用开发工作流（以 v0 为例）：&lt;/strong&gt;
现代 AI 代理工作流已经涵盖了：意图理解 -&gt; 上下文组装（收集现有代码组件） -&gt; 生成代码 -&gt; 验证测试 -&gt; 人在回路 (Human-in-the-loop) 审查与反馈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLM在编程时的局限性&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLM概率模型，但是需要&lt;strong&gt;确定性的框架&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;知识过时问题如何解决：流式操纵：直接建立子系统在到达用户前打补丁&lt;/li&gt;
&lt;li&gt;sft&amp;#x26;&amp;#x26;rl去加
&lt;strong&gt;Future&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;工具生态：目前的 AI 开发工具正处于爆发期，分为代码助手（如 GitHub Copilot）、前端构建器（如 v0, Lovable）和可视化开发平台等。&lt;/li&gt;
&lt;li&gt;核心差异化：未来的关键区别在于&lt;strong&gt;端到端的工作流 (End-to-end workflows)&lt;/strong&gt;，即 AI 不仅是自动补全建议，而是处理从测试、部署到监控的整个生命周期。&lt;/li&gt;
&lt;li&gt;实际影响：初创公司可以在几天而非几个月内发布 MVP；企业能够更现代化地处理遗留系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;AI 维护&lt;/h1&gt;
&lt;p&gt;ai未来可能会转向维护的工作，减少做苦力活的内容，
当前核心痛点：软件工程中的“苦力活” (Grunt Work)**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;70/30 比例：软件工程师实际上有 &lt;strong&gt;70% 以上&lt;/strong&gt; 的时间花在“苦力活”上（如查询日志、建立上下文、收集证据、协调沟通、合规性检查、待命值班），只有不到 30% 的时间用于“创造性工作”（如解决问题、优化、设计决策）
这会让人非常==疲惫==，但是生产级的ai&lt;/li&gt;
&lt;li&gt;prompt不够，还需要domain knowledge&lt;/li&gt;
&lt;li&gt;上下文窗口的限制，mcp，eval不容易
希望未来的话，软件工程会转向纯纯的代理&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;总的来说，ai in software深入下去还是有更多的工程管理上的内容，相信等到我未来进行一些大型项目时，会有更多的体会&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>我的网站建立过程</title><link>https://bauklotze.vercel.app/blog/daily-life/my-website</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/daily-life/my-website</guid><description>My Website construction</description><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;https://axi404.top  我基于他的东西去建站的&lt;/p&gt;
&lt;h2&gt;about website comment settings&lt;/h2&gt;
&lt;p&gt;参见 https://axi404.top 中的相关内容&lt;/p&gt;
&lt;p&gt;https://bauklotze-comment.vercel.app/ui 就可以看到一堆的评论了&lt;/p&gt;
&lt;h2&gt;建站日程&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;icon寻找&lt;/strong&gt;: https://worldvectorlogo.com/search/obsidian&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一些有用的网站&lt;/strong&gt;
https://docs.astro.build/zh-cn/basics/astro-pages/#%E5%9F%BA%E4%BA%8E%E6%96%87%E4%BB%B6%E7%9A%84%E8%B7%AF%E7%94%B1 astro基于文件的路由&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;https://docs.astro.build/zh-cn/basics/astro-pages/#astro-%E9%A1%B5%E9%9D%A2 astro页面html语法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;关于头像&lt;/strong&gt;： gemini+ https://www.photopea.com/ 变透明&lt;/li&gt;
&lt;li&gt;自动颜色提取，使用pnpm dev就可以了(predev中加上了一个有趣的json文件)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="/_astro/cz3.DgFxHhQX.webp"/><enclosure url="/_astro/cz3.DgFxHhQX.webp"/></item><item><title>LLM4Rec:Deep Learning era</title><link>https://bauklotze.vercel.app/blog/alpha-lab/rec-paperlist1/rec-paperlist1</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/alpha-lab/rec-paperlist1/rec-paperlist1</guid><description>LLM4Rec: Deep learning时代</description><pubDate>Sat, 07 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;NCF (Neural Collaborative Filtering)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;arXiv: 1708.05031
&lt;img src=&quot;./images/Rec-paperlist1_2026-02-08-15.png&quot; alt=&quot;NCF&quot;&gt;&lt;/li&gt;
&lt;li&gt;概览：提出 NCF 框架，用神经网络学习用户与物品的交互函数，替代矩阵分解中的内积形式，并通过多层感知机增强非线性表达。实验显示在真实数据集上显著优于多种传统与深度推荐方法，且更深的网络结构带来更好效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;NGCF&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;arXiv: 1905.08108
&lt;img src=&quot;./images/Rec-paperlist1_2026-02-08-16.png&quot; alt=&quot;NGCF&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;概览：将用户-物品二部图结构显式引入嵌入学习，通过在交互图上传播嵌入来捕获高阶连通性与协同信号。大量实验显示 NGCF 在多个公开基准上超过已有方法，并分析了嵌入传播对性能提升的关键作用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;LightGCN&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;arXiv: 2002.02126
&lt;img src=&quot;./images/Rec-paperlist1_2026-02-08-16%201.png&quot; alt=&quot;LightGCN&quot;&gt;&lt;/li&gt;
&lt;li&gt;概览：发现 GCN 中的特征变换与非线性激活对推荐贡献有限，反而增加训练难度。LightGCN 仅保留邻居聚合，以线性传播学习用户与物品表示，并使用多层嵌入加权求和作为最终表示，在相同设置下显著优于 NGCF 等模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;MMGCN&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;acm: https://dl.acm.org/doi/10.1145/3343031.3351034
&lt;img src=&quot;./images/Rec-paperlist1_2026-02-08-16%202.png&quot; alt=&quot;MMGCN&quot;&gt;&lt;/li&gt;
&lt;li&gt;概览：多模态的用户信息输入然后输出&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SASRec&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;arXiv: 1808.09781
&lt;img src=&quot;./images/Rec-paperlist1_2026-02-08-17.png&quot; alt=&quot;SASRec&quot;&gt;&lt;/li&gt;
&lt;li&gt;概览：提出基于自注意力的序列推荐模型 SASRec，通过注意力机制在用户历史中选择相关行为，在捕获长期语义的同时保持对近期行为的敏感性。实验显示其在稀疏与稠密数据上均优于多种序列模型，并具有更高的效率。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="/_astro/background.BdQE_IJL.jpg"/><enclosure url="/_astro/background.BdQE_IJL.jpg"/></item><item><title>James Harden:From Clippers to Cavaliers</title><link>https://bauklotze.vercel.app/blog/daily-life/from-clippers-to-cavaliers/from-clippers-to-cavaliers</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/daily-life/from-clippers-to-cavaliers/from-clippers-to-cavaliers</guid><description>James Harden:从快船到骑士</description><pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;从2022年开始看NBA,到现在，差不多也有3年的时间了，而James Harden, 一位曾经的MVP,曾经单核对抗宇宙勇的巨星，这3年内也经历了2次转会。
为什么我会喜欢上James Harden呢，高中的时候，我的一个好哥们，天天在我耳边说100遍76人总冠军，哈登MVP,然后我就喜欢上了James Harden。但是当我真正开始看NBA,了解James背后的故事，那种没有老大的心气，但是有老大的能力，以及总是在关键时刻掉链子，被人们诟病季后赛软蛋的人，真的和我们一摸一样。&lt;/p&gt;
&lt;p&gt;76人时期，刚刚开始看NBA,只知道天天喊76人总冠军，哈登MVP, 哈登也拿到了常规赛助攻王，恩比德也拿到了MVP,还有哈登的小跟班马克西，常规赛，东部第三，季后赛，首轮横扫篮网，而到了第二轮，恩比德伤了。对阵波士顿凯尔特人，单核，用2场40+以及准绝杀回应所有人。但是，独木难支，抢七的时候，可以理解的由于体力的过度消耗命中率下降，又一年，失败。&lt;/p&gt;
&lt;p&gt;那个休赛季，由于和76人在薪资上的问题，哈登来到了快船。哈登，威少，伦纳德，保罗乔治，宇宙战舰启航，虽然开赛的时候磨合不足，但是接下来一度冲到了西部第一，最后西部第4.当时的快船，全员健康，但是问题在于后卫线上的防守不足，缺少持球点，导致独行侠对哈登的过度包夹，以及泡椒的不稳定，小卡的又一年的医保卡，板凳席没人站出来，内线祖巴茨独木难支，再一次失败。&lt;/p&gt;
&lt;p&gt;下一个赛季，也是让我感觉最喜欢的快船，全员:哈登，祖巴茨，鲍威尔，邓恩，小琼斯，全部的草根球员，对手给哈登无限的上包夹，哈登只能投出来看上去非常差劲的命中率，每天晚上打38min，因为哈登一下场，就陷入进攻慌。哈登又一次开始了火箭登模式，只是这一次，他不再年轻。，首发5人中没有1人年薪上2000万，几乎都是别的球队只能说合格轮换球员，但他们硬是打出了全联盟最强的防守效率之一。即使是全场比赛都是进攻断电，但是到最后，凭借哈登不断地造犯规&amp;#x26;&amp;#x26;三分，还是帮快船稳住了战绩。直到伦纳德复出，绝杀国王，北伐，到最后一场地大战勇士，哈登和伦纳德战胜库里和巴特勒，以西部第五地身份进入季后赛。
季后赛，甚至大家都以为要快船总冠军了，战神卡归位，2:1，直到戈登地补扣绝杀。快船缺少年轻地锋线导致伦纳德过度消耗体力，但是G6哈登又一次站了出来，只是这一次还是奇迹不现，G7全员哑火，没有队友站出来，又一年地失败。
&lt;img src=&quot;./images/Basketbal%20James%20Harden_2026-02-06-07.png&quot; alt=&quot;James Harden in Clippers&quot;&gt;&lt;/p&gt;
&lt;p&gt;今年地快船，进行了大量地应援，开赛地6胜21负，所有地胜利只能靠哈登地爆发，到后来的战神卡归位，到突如其来的交易，不管怎么说，只能说快船，除了管理层不是人，别的都是完美的，老大哥以及一堆地下的小弟，那支快船已经永远的封存在了我们的记忆中。不过好在最后的快船和哈登，非常和平的分手了，让我们这些球迷再一次看到了奇迹，看到了什么叫逆袭，快船让哈登重返巅峰，大大改善了哈登的舆论，让哈登重新找回自己，而哈登也给快船带来了新的文化，“I am a system”&lt;/p&gt;
&lt;p&gt;不过路还是要走的，骑士也终于迎来了詹姆斯，希望我们的登哥可以在生涯赢下那座总冠军，那必定是和诺维茨基一样的总冠军。
&lt;img src=&quot;./images/Basketbal%20James%20Harden_2026-02-06-09.png&quot; alt=&quot;James Harden in Cavaliers&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BLQ97SiQ.png"/><enclosure url="/_astro/background.BLQ97SiQ.png"/></item><item><title>大二上总结</title><link>https://bauklotze.vercel.app/blog/reflections/25fall-summary/25fall-summary</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/25fall-summary/25fall-summary</guid><description>大二上总结</description><pubDate>Wed, 21 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一次写文章转眼已经是快2个月前的事情了，这两个月内，感觉我的生活发生了天翻地覆的变化。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;&lt;strong&gt;ai课程完成情况&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;cs224n NLP Basic: 完成基本上所有的lecture，proj的学习。基本补齐了pre-rnn以及rnn到llm中的历史。&lt;/li&gt;
&lt;li&gt;cs61b Data Structure: 在阅读cs224n的课后paper时，意外发现了自己在cs61b上的薄弱。于是完成了包括slides,hw&amp;#x26;&amp;#x26;lab&amp;#x26;&amp;#x26;proj的完成，并且将所有内容push到了github仓库中。&lt;/li&gt;
&lt;li&gt;cs224W GNN: 完成约一半的lecture及几个hw，&lt;/li&gt;
&lt;li&gt;cs336 LLM: 完成了1/4的lecture观看，简直是大彻大悟，就差实践了。
别的原本预定的计划:&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;科研&amp;#x26;&amp;#x26;other&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;paper&amp;#x26;&amp;#x26;讲座: 阅读了20-30篇paper,包括LLM基础及目前我的研究方向的若干经典论文，可以算是入门了吧。听了大量的讲座，对包括多模态，具身，生成等方面有了基本的认知。&lt;/li&gt;
&lt;li&gt;个人工作流整理: 受到东川路第一依蕾娜，来自xjtu的axi的启发，开始调整自己的工作流(科研，课程，生活),并且开始用不同的眼光看待一切。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小小的帮扶活动&lt;/strong&gt;: 帮扶xdx淑芬并且手写大量讲义，最后效果也不错(xdx应该有4.3了吧)。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;美中不足的地方&lt;/strong&gt;&lt;/h2&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;strong&gt;工程能力提高约等于0&lt;/strong&gt;: git操作，linux,docker,以及如今最新的生产力工具claude code,cursor等还未开始使用。寒假好好学学&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GRE单词背诵量仍然为0&lt;/strong&gt;: 只能硬挤时间了，&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;课内，自学课程，科研paper阅读整理为0&lt;/strong&gt;: 课内7门主课(7篇文章)，自学课程，包括cs61b数据结构，工程思维，proj,cs224n(关于语义，hw中的有趣的发现),cs224w(一车的需要整理的东西)，总共10余篇paper吧。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结下来，这个学期我对自己的进度还算满意，只是output严重不足,自我迭代速率太慢，但是突破自己舒适圈，初步接触科研，还是挺不错的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;&lt;strong&gt;寒假的任务&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;寒假的话，除了科研任务，更多是提升自我，包括工程能力以及继续完成在9月给自己的任务。只局限于科研，会把自己的视野锁死，而通过自学课程，才能提升自己的整体能力。
科研任务: 根据师兄的安排，可能会看1145141919810篇paper。等到寒假结束后就可以参与到前沿工作中啦！
Stanford CS336:神课，完整实现llm的每一个组件，钱也算是有地方花了
Stanford CS224W: GNN作为唯一没有被完全攻破的网络结构，未来的潜力只能说是非常大。尤其是在推荐中。
工程能力提高计划: 包括stanford cs146S，以及一些工程项目的实现。新时代要拥抱新的生产力工具，而且以上在下个学期的科研中会更加重要。这个寒假是个好时机
Information Theory by MacKay: 阅读paper时越来越感觉用信息传播去理解时非常重要的。相信学完这门课，对各种paper会有不同的理解&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;越来越感觉时间不够用了，希望自己可以成功的将以上任务完成，同时对整个当前ai行业有更全面的了解。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.DNzgYXZo.jpg"/><enclosure url="/_astro/background.DNzgYXZo.jpg"/></item><item><title>CS224N: Between Transformer and GPT4</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs224n-transformer-gpt4/cs224n-transformer-gpt4</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs224n-transformer-gpt4/cs224n-transformer-gpt4</guid><description>深入探讨Transformer到GPT4之间的技术演进，包括模型预训练、微调技术和LLM训练的重要里程碑。</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我们已经知道了什么是transformer了，但是在transformer只是只是对于输入信息的理解更加深刻，而输出的时候还是以一个比较”天真“的方式，一个一个token进行输出。因此在学完transformer之后，自然就会像&lt;strong&gt;transformer和GPT4之间的东西是什么&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;模型预训练&lt;/h2&gt;
&lt;p&gt;cs224n的lecture8,9,10,11就解答了这个问题，介绍了从17年的transformer到如今的24年这7年中的重要milestone以及如今LLM训练的常见步骤。&lt;/p&gt;
&lt;p&gt;我们的LLM的大体训练步骤为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先通过&lt;strong&gt;有趣的数据集&lt;/strong&gt; ，训练出来一个原始模型&lt;strong&gt;base-model&lt;/strong&gt; ，其目的是&lt;strong&gt;理解语言+世界知识&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型微调&lt;/strong&gt; ：&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;专业任务微调：由bert开创，通过固定参数以及添加少量参数可以大大在base model上提升相关能力，目的是为了提升&lt;strong&gt;专业的能力&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;指令微调：通过** 特殊的数据集**教会模型学会进行推理的思考&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;强化学习阶段&lt;/strong&gt; ：为了让模型可以响应人类的指令，我们需要设置一个奖励函数来对模型的参数进行进一步的调整&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;R(x,y)用来表示人类对于在x条件下产生y的喜好程度，我们使用它对于原有模型进行进一步的修正&lt;/li&gt;
&lt;li&gt;RLHF: 使用强化学习进行这一个步骤&lt;/li&gt;
&lt;li&gt;DPO: 结构简单的，性价比高的简化RLHF&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;评测方式&lt;/strong&gt; ：评测的方式有非常多，而有几个非常有趣的评测&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;zero-shot learning &amp;#x26;&amp;#x26; few-shot learning: 让模型学会如何通过比较少的数据中得到一个普遍的规律&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构建base-model的过程就是耳熟能详的预训练，而模型微调则是我们的后训练阶段。pre-training预训练&lt;/p&gt;
&lt;h3&gt;word的表示形式&lt;/h3&gt;
&lt;p&gt;回忆一下传统的词语的表示方式，使用one-hot去表示(语义不明显，而且当词语数量非常大时，空间浪费)，再往后，使用训练好的word2vec将每一个词语对应成一个向量，但是&lt;strong&gt;问题还是&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;p1:&lt;/strong&gt; 对于没有见过的词语没有变成相应的向量，比如&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;taaaaaaaaasty-&gt;UNK(unkown),显然这个是为了加强语气表示的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;p2:&lt;/strong&gt; 忽略了词语是由sub-word组成的，比如&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;un_natural_linguistic_representation-&gt;UNK(unknown)，对于这种由大量词缀组成的词语，还是会变成UNK。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;p3:&lt;/strong&gt; 同时使用传统的word2vec，我们的one-hot-&gt;vec的矩阵应该和上下文有关，因此理论上应该&lt;strong&gt;放到模型中一起训练&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于第3个问题，我们只要在原有的transformer上面进行如下改进即可&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;而对于第1，2个问题，我们将会使用** sub-word&lt;strong&gt;处理输入，而常见的算法是&lt;/strong&gt; byte-pair encoding**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初始的词表只有26个字母&lt;/li&gt;
&lt;li&gt;统计词表中 $x_1,x_2$ 同时出现的概率，将其中最为常见的两个 $x_i,x_j$ 的组合 $x_i,x_j$ 作为新的结果存储近词表，并且进行合并&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;example&lt;/strong&gt; :如果语料为low,lower,newest,widest&lt;/p&gt;
&lt;p&gt;ite1:经过统计，(e,s)出现的最多，将(es)添加到词表&lt;/p&gt;
&lt;p&gt;以此类推，最后可以将语料变成&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lower → low er
newest → new est
widest → wid est
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;模型预训练+微调机制&lt;/h3&gt;
&lt;p&gt;传统的RNN是在word2vec(固定的词向量)输入上对于模型进行训练，而这个固定的词向量可以认为是一种特殊的&lt;strong&gt;预训练&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而对于大型的LLM的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预训练就是&lt;strong&gt;对于整个模型在预训练数据集继续训练&lt;/strong&gt; ，而在此基础上&lt;/li&gt;
&lt;li&gt;模型微调&lt;strong&gt;以预训练结果为初始参数再进行训练&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种训练体制是在&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//arxiv.org/abs/1810.04805&quot;&gt;Bert&lt;/a&gt;这篇论文提出的&lt;/p&gt;
&lt;h3&gt;why fine-tune&lt;/h3&gt;
&lt;p&gt;** 为什么&lt;strong&gt;我们要使用模型微调？之前我们的模型训练时都要使用非常复杂的数据集合，我们将&lt;/strong&gt; 介绍世界知识&lt;strong&gt;以及传授&lt;/strong&gt; 重要的能力&lt;strong&gt;的数据集合一起传递给模型，会导致&lt;/strong&gt; 数据集利用不充分**。&lt;/p&gt;
&lt;p&gt;因此我们将模型训练分成预训练以及模型微调两个步骤，对于两个阶段使用的数据的** 质量和精度**有所不同。&lt;/p&gt;
&lt;p&gt;预训练数据集构造方式** 非常简单，数据容易寻找，同时可以高效学习到关于世界的基本知识**&lt;/p&gt;
&lt;p&gt;而** fine-tune&lt;strong&gt;则是将原有模型在&lt;/strong&gt; 特别的数据集**，对于模型的** 特殊位置进行参数调整**，进行再训练(当然，会在输出部分进行略略的添加一些参数)。&lt;/p&gt;
&lt;p&gt;而bert表明** 使用fine-tune&lt;strong&gt;的模型对于特定的任务的表现比同参数量的模型性能有&lt;/strong&gt; 明显的提升**。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;我们常见的两种transformer架构:** encoder only&lt;strong&gt;以及&lt;/strong&gt; decoder only**，分别对应不同的** 预训练数据集构建**，下面以GPT以及Bert为例子进行介绍&lt;/p&gt;
&lt;h3&gt;Encoder only(Bert及其衍生)&lt;/h3&gt;
&lt;p&gt;encoder only的架构可以对于输入的数据进行全面的理解，我们的Bert是构建了** 预测任务**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于像“I went to the store”这样一句话，将“I ___ to the store”作为输入，然后进行监督学习&lt;/li&gt;
&lt;li&gt;使用的原始的语料库为&lt;strong&gt;bookcorpus&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，原始论文中，不是直接挖空，而是对一个句子中** 15%的词语进行预测**，包括 $80% mask, 10% random, 10% unchanged$&lt;/p&gt;
&lt;p&gt;之后也有非常多的改进任务，包括构建不同的** 预训练数据集**，但总的来说，encoder only model的预训练数据集大都是** 根据上下文对于部分进行预测**&lt;/p&gt;
&lt;h3&gt;Decoder-Encoder(T5及其衍生)&lt;/h3&gt;
&lt;p&gt;这一块的代表作品是2018的&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//arxiv.org/abs/1910.10683&quot;&gt;T5 model&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;而它的预训练数据集构建方式是** 随机掩盖连续的文本片段，并且通过decoder输出模型被掩盖的部分**&lt;/p&gt;
&lt;p&gt;实验结果表明，T5在NLP相关任务上面表现异常优异。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Decoder only（GPT及其衍生）&lt;/h3&gt;
&lt;p&gt;** GPT1&lt;strong&gt;主要进行的是&lt;/strong&gt; 判断是否是两个句子是否是相连的任务**，具体构造方式为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于一段连着的句子” The man is in the doorway The person is near the door“&lt;/li&gt;
&lt;li&gt;通过对于前半句话”The man is in the doorway“，后半句”The person is near the door“进行不同的标签区分句子，最后进行预测任务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;GPT2&lt;/strong&gt; 的使用了类似的数据构造方式，但是规模更大(数据集扩大了10倍)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GPT3&lt;/strong&gt; 则是让模型进行&lt;strong&gt;in-context learning&lt;/strong&gt; ，目的是提升模型的&lt;strong&gt;提取规律能力&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比如输入为&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;1+1=2
  2+4=6
  4+5=9
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;然后要求回答进行”2+3=？？？“的预测任务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上我们介绍了预训练部分，当前我们的模型越来越大，所需要的参数量也越来越大，而由&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//arxiv.org/abs/2001.08361&quot;&gt;Scaling laws , Kaplan,et&lt;/a&gt;告诉我们，同种模型参数量和loss成正比。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;当今的模型也从Bert的几亿参数，几十亿token训练数据到现在的参数动辄几百亿。预训练阶段，&lt;strong&gt;就需要平衡好其参数量和token的关系，才能达到最好的效果。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;模型微调方法&lt;/h2&gt;
&lt;p&gt;以上是预训练部分，接下来就要进行** 模型的微调**(这一块我还没有深入挖掘，只能列举一些常见的，lecture中提到的技术)&lt;/p&gt;
&lt;p&gt;模型微调能教会模型各种各样的能力，包括** 翻译，计算，。。。&lt;strong&gt;，为了得到不同的能力，我们会设计&lt;/strong&gt; 大量的微调数据集,使用不同的技术**锻炼模型的能力。&lt;/p&gt;
&lt;h3&gt;模型微调方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ful-finetuning:对于全部的参数进行微调，&lt;strong&gt;风险最大，算力要求高，但是效果最好&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;prefix-tuning&lt;/strong&gt; :在&lt;strong&gt;每一层的（Q,K,V)&lt;/strong&gt; 上添加一些pre-paramseters并且使用我们的数据集进行微调&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;prompt tuning&lt;/strong&gt; :在&lt;strong&gt;input&lt;/strong&gt; 中添加一些prompt，并且添加一些可以学习的参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LoRA微调&lt;/strong&gt; ：直接对于一个 $W=R^{x\times y}$ 的矩阵进行微调可能参数量过大,但是如果我们可以进行间接调整： $A=R^{x\times k},B=R^{k\times y}$ ,从而用 $W=W+AB$ 去替代，就可以大大的减少计算量，这种技术也被称为是&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//arxiv.org/abs/2106.09685&quot;&gt;Lora&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上只是一些可行的方向，之后我会阅读更多论文来得到更加全面的理解&lt;/p&gt;
&lt;h3&gt;泛化能力&lt;/h3&gt;
&lt;p&gt;世界上有各种各样的能力，我们不可能将所有的东西全部交给ai，ai也需要有自己的理解，然后就是最为神奇的一点：对于一个模型在它&lt;strong&gt;从没有见过的东西上，也有解决它的能力！！！&lt;/strong&gt; ，更进一步的，&lt;strong&gt;如果我们给出几个案例，那么LLM可以提取出一般的规律，并且得到非常好的结果！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以上这两点就是** zero-shot&amp;#x26;&amp;#x26;few shot learning**，而进一步的我们如果添加上一定的指令之后，通过设置不同的指令，可以有非常有趣的结果，比如在论文&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//arxiv.org/abs/2205.11916&quot;&gt;Large language models are reasoners&lt;/a&gt;中可以发现&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在添加了”let’s think step by step”之后，模型准确率大幅提升！！！！！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;关于zero(few)-shot, cot的理解我在阅读了相关论文之后会给出更多的解答，但是总结而言&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;通过大量的模型微调，模型可以获得一定的理解解答问题的能力&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用prompt可以对于模型的行为产生非常大的影响&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Post training&lt;/h2&gt;
&lt;p&gt;从基本的预训练以及模型微调阶段，我们的模型已经学会了世界的基本知识，而且具有了解决一些特定任务的能力，但是这和我们使用到的** 善解人意，按照我们指示回答的GPT&lt;strong&gt;好像还有一定的差距，这就需要进行&lt;/strong&gt; post-training**,我们的post-training主要包括** 指令微调&lt;strong&gt;以及&lt;/strong&gt; 强化学习**两个部分&lt;/p&gt;
&lt;h3&gt;指令微调&lt;/h3&gt;
&lt;p&gt;所谓的指令微调，就是制造大量的(instruction, pair)的对子，包含人的指令以及应该做出怎么样的回答，通过这种方式就可以让模型** 学会应该如何回答问题**&lt;/p&gt;
&lt;p&gt;课堂中有个例子&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;在instruction finetuning之前，模型什么都回答不出来，而之后可以发现模型开始学会贴合人的思考方式了&lt;/p&gt;
&lt;h2&gt;强化学习阶段&lt;/h2&gt;
&lt;p&gt;只用指令微调我们只能让模型** 听懂人话**，但是只有通过强化学习，模型才能做出符合人类价值与偏好的输出。&lt;/p&gt;
&lt;p&gt;而我们的实现方式有两种，** RLHF**(reinforce learning human preference)&amp;#x26;&amp;#x26;** Dpo**(简化的RLHF)&lt;/p&gt;
&lt;h3&gt;RLHF&lt;/h3&gt;
&lt;p&gt;RLHF的流程如下，接下来我们就每一个步骤进行介绍&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_08.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Part 1:数据集构建&lt;/h3&gt;
&lt;p&gt;使用强化学习进行微调，自然需要设立** 能反映人类的喜好程度的奖励函数**，这自然可以请人去标注数据&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;try1:&lt;/strong&gt; 比如模型生成一个答案，问一个人”你会打1-10中的几分”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点是这种方式的噪声非常大，不同人的打分标准不同，有人可能觉得9分就挺高的，有的人觉得7分已经不错了&lt;/p&gt;
&lt;p&gt;真实的RLHF的数据集的构建，让人打分非常困难，但是让人&lt;strong&gt;判断两个中那个相对简单比较容易&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比如有模型做出两个回答 $y_1,y_2$ ，人认为 $y_1&gt;y_2$ 这就是一组数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用这种方法，数据集就是 $D=(x,y^w,y^l)$&lt;/p&gt;
&lt;h3&gt;Part2:奖励函数训练&lt;/h3&gt;
&lt;p&gt;但是通过这种方式我们只能生成对于 $数据集中的y的奖励$ ，我们想要对于&lt;strong&gt;所有的模型输出y都进行奖励预测&lt;/strong&gt;,因此我们就需要对于** 奖励函数进行训练**&lt;/p&gt;
&lt;p&gt;由** Bradley-Terry的心理学论文**知，可以用 $log\sigma(RM_\phi(x,y^w)-RM_\phi(x,y^w))$ 是人类对于 $y_w&gt;y_l$ 时内心的衡量标准。&lt;/p&gt;
&lt;p&gt;因此对于奖励函数的训练的损失函数变为&lt;/p&gt;
&lt;p&gt;$ J_{RM}(\phi) = -\mathbb{E}&lt;em&gt;{(x,, y^w,, y^l) \sim D} \left[ \log \sigma(RM&lt;/em&gt;\phi(x, y^w) - RM_\phi(x, y^l)) \right] $&lt;/p&gt;
&lt;p&gt;从而有了训练之后的** 奖励函数** $RM_\phi (x,y)$&lt;/p&gt;
&lt;h3&gt;Part3:强化学习部分&lt;/h3&gt;
&lt;p&gt;RL核心是** 希望奖励函数** $RM_\phi(x,y)$ ** 减小生成那些让人不满意答案的概率**，从而将** 人类偏好**也作为信息编入模型中&lt;/p&gt;
&lt;p&gt;因此我们的RL就是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;奖励函数 $RM_\theta(x,\hat{y})$ (已经训练好了)&lt;/li&gt;
&lt;li&gt;期望： $\mathbb{E}&lt;em&gt;{\hat{y} \sim p&lt;/em&gt;{\theta}^{RL}(\hat{y}|x)} \left[ RM_{\phi}(x, \hat{y}) \right]$ 我们希望最大化这个东西&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是事实发现，我们如果这样的话&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;会生成非常多的迎合人类喜好且不回答问题的答案&lt;/li&gt;
&lt;li&gt;我们&lt;strong&gt;原本的模型还不错，我们不希望改进之后的&lt;/strong&gt; $p_\theta(x|y)$ ** 偏离** $p(x|y)$ ** 太多**&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此加上一个log的损失项目之后的RL阶段的期望便是&lt;/p&gt;
&lt;p&gt;$ \mathbb{E}&lt;em&gt;{\hat{y} \sim p&lt;/em&gt;{\theta}^{RL}(\hat{y} \mid x)} \left[ RM_{\phi}(x, \hat{y}) - \beta \log \left( \frac{p_{\theta}^{RL}(\hat{y} \mid x)}{p^{PT}(\hat{y} \mid x)} \right) \right] $&lt;/p&gt;
&lt;h3&gt;DPO&lt;/h3&gt;
&lt;p&gt;可以发现，RLHF是非常** 复杂**的，我们还需要通过中间奖励函数的训练，我们希望可以直接通过人类标签的数据集改进原始的参数，因此我们做出了一个比较合理的假设。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;step1:&lt;/strong&gt; 我们直接对于RL中的期望使用&lt;strong&gt;变分法&lt;/strong&gt; (p(y|x)的和为1为约束)，得到在给定的 $RM_{标签数据}(x,y)$ 上的最佳结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ p^*(\hat{y} \mid x) = \frac{1}{Z(x)} p^{PT}(\hat{y} \mid x) \exp\left( \frac{1}{\beta} RM(x, \hat{y}) \right) $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;step2:因此理论上，训练得到的奖励函数就是&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ RM_\theta(x, \hat{y}) = \beta \log \frac{p_\theta^{RL}(\hat{y} \mid x)}{p^{PT}(\hat{y} \mid x)} + \beta \log Z(x) $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;step3:&lt;/strong&gt; 从而我们可以使用监督学习去进行参数优化，损失函数就是&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ J_{DPO}(\theta) = -\mathbb{E}&lt;em&gt;{(x,, y^w,, y^l) \sim D} \left[ \log \sigma\left( RM&lt;/em&gt;\theta(x, y^w) - RM_\theta(x, y^l) \right) \right] $&lt;/p&gt;
&lt;p&gt;当然RLHF/DPO会有一定危害，具体可以参考视频&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//www.youtube.com/watch%3Fv%3DqV_rOlHjvvs&quot;&gt;horny gpt&lt;/a&gt;便是一个非常好的讲解视频&lt;/p&gt;
&lt;p&gt;以上就是我们的大概流程，而对于每个阶段的重要论文&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模型预训练提出者Bert&lt;/li&gt;
&lt;li&gt;模型预训练数据集构建：Bert,T5,GPT&lt;/li&gt;
&lt;li&gt;测试数据集合构建：zero-shot,few-shot&lt;/li&gt;
&lt;li&gt;提示词微调鼻祖：zero-shot CoT论文&lt;/li&gt;
&lt;li&gt;RLHF&amp;#x26;&amp;#x26;DPO&lt;/li&gt;
&lt;li&gt;一系列的模型微调论文&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="/_astro/background.BdQE_IJL.jpg"/><enclosure url="/_astro/background.BdQE_IJL.jpg"/></item><item><title>CS224W(1): ML图特征设计</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs224w-ml-graph-feat-design/cs224w-ml-graph-feat-design</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs224w-ml-graph-feat-design/cs224w-ml-graph-feat-design</guid><description>机器学习图特征设计的详细介绍，包括图结构分析和特征工程技巧。</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;cs224w的lecture1-2主要介绍了graph deep learning的任务，以及&lt;strong&gt;图的几何结构&lt;/strong&gt; 特征的设计思路&lt;/p&gt;
&lt;p&gt;不同于传统的序列的文字，或者网格的图片，实际中的数据，如人际关系，都是以&lt;strong&gt;graph&lt;/strong&gt; 的形式呈现的。ML in Graph所进行的任务，自然便是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;节点node, 边edge, 以及子图graph表示方法&amp;#x26;&amp;#x26;任务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而ML的任务是&lt;strong&gt;为nodes/links/graphs&lt;/strong&gt; 设计一些特征，而接下来的讨论中，会为设计特征提供一些思路&lt;/p&gt;
&lt;h2&gt;节点node tasks&amp;#x26;&amp;#x26;features&lt;/h2&gt;
&lt;p&gt;对于上面一张图，我们的节点有那些需要考虑的特征呢，像&lt;strong&gt;度，周围的节点聚集程度，这个节点在那些部分的子图中&lt;/strong&gt; ，这些都是可能入手的考虑方法&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;度&lt;/strong&gt; ：节点的&lt;strong&gt;度&lt;/strong&gt; ，即为邻居节点的个数自然是可以考虑的对象，上图中 $d_A=1,d_B=2,d_C=3,d_D=4...$ 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是缺点是&lt;strong&gt;没有区分其邻居节点&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点聚集度:&lt;/strong&gt; 这个性质反映了节点是否在图的中心，比如上图D就是在中心，但是a显然不是&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;** 特征值中心**: 我们需要区分** 节点的重要程度**,自然想到了将** 邻居的值全部加起来**。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;设节点v的值为 $c_v$ ，那么有 $c_v=\dfrac{1}{\lambda} \Sigma_{u\in N(v)} c_u$&lt;br&gt;
因此有 $\lambda c=Ac$ ,其中A为邻接矩阵，** 最大的 $\lambda$ 应的特征值&lt;strong&gt;就反映了&lt;/strong&gt; 聚集程度**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;** 路径中心**: 如果一个节点在G的中心，那么应该有更多的路径经过它，于是对于** 是否在最短路径中**是一个可以考虑的标准&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$c_v=\Sigma \dfrac{# s到t的最短路径中含有v}{# s到t的最短路径}$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;举个例子，上图中考察 $c_c$ =3,因为(A-C-B,A-C-D,A-C-D-E)中包含C这个点&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;最短路径&lt;/strong&gt; : 对于在中心的点，到&lt;strong&gt;到别的节点的距离应该比较近&lt;/strong&gt; 因此有&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$c_v=\dfrac{1}{\Sigma_u u到v的最短路径长度}$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;举个例子，上图中，如果不考虑hgf的话， $c_A=1/(2+1+2+3)=1/8$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;聚类程度&lt;/strong&gt; :单单只看节点v和它的邻居显然不够，如果一个节点在图的中央，&lt;strong&gt;那么它的邻居之间应该也有比较多的边&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​ 因此有 $e_v=\dfrac{# v的邻居之间的边数目}{C_2^{d_v}}$&lt;/p&gt;
&lt;p&gt;比如&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特殊子图考虑&lt;/strong&gt; ：再次观察聚类程度，我们实际上是在考虑三角形&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;​ 之前高中数学竞赛的时候，有的时候像&lt;strong&gt;角，四边形等&lt;/strong&gt; 也是常见的思考模型，因此&lt;strong&gt;特殊子图graphlets&lt;/strong&gt; 也是反映节点的重要性质之一&lt;/p&gt;
&lt;p&gt;​ 最为常见的一个特征&lt;strong&gt;子图向量&lt;/strong&gt; : 计算包含节点v的特殊子图的个数&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;考虑如图的G中v的子图向量，包含v的子图a,b,c,d分别有2，1，0，2个，因此[2,1,0,2]就可以反映这个特征&lt;/p&gt;
&lt;p&gt;以上是一些常见的将图结构转换成节点信息的方式。&lt;/p&gt;
&lt;h2&gt;关系link tasks&amp;#x26;&amp;#x26;features&lt;/h2&gt;
&lt;p&gt;关系预测也有非常多的应用，比如社会关系的预测，朋友的朋友是不是朋友等。接下来是点之间关系特征设计的可以考虑的思路&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;最短路径&lt;/strong&gt; : 对于点与点之间关系，最短距离显然是需要考虑的。(但是对于路径数量等都没有区分)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;比如上图中 (A,B)=2,(B,G)=3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;路径数量&lt;/strong&gt; :我们可以发现，&lt;strong&gt;邻接矩阵A&lt;/strong&gt; 有 $A^n_{uv}$ 表示了u到v的长为n的路径的数量(参考markov链的性质)。因此可以&lt;strong&gt;将路径数量整体作为反映图性质的因素&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ S_{V_1V_2}=\Sigma^{\infty}&lt;em&gt;{l=1}\beta^l A&lt;/em&gt;{v_1v_2}^l\ \Rightarrow S=\Sigma^{\infty}_{l=1}\beta^l A^l=(I-\beta A)^{-1}-I $&lt;/p&gt;
&lt;p&gt;​ 即可将** 长度，路径数量都考虑进去**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点的共同的邻居数量:&lt;/strong&gt; 顾名思义，也是可能的因素之一&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;图graph features&amp;#x26;&amp;#x26;tasks&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt; ：找到一些可以反映整张图的features&lt;/p&gt;
&lt;p&gt;我们要计算图G,G’之间的相似度，可以使用类似SVM的想法， $K(G,G&apos;)=\phi (G)^T \phi (G&apos;)$ ,因此我们只需要&lt;strong&gt;设计 $\phi$&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;子图特征&lt;/strong&gt; ：类似于node中的子图向量，&lt;strong&gt;如果我们事先规定一些特别的子图，并且在图G中计算他们的数量作为图的特征&lt;/strong&gt;, 比如如图的k=4的1个graphlet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;​ 但是对于图越大，这个f肯定越大，因此需要做一个normalization: $h_g=\dfrac{f_G}{sum(f_G)}$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;W-L kernel&lt;/strong&gt; : wl kernel的设计思路类似于&lt;strong&gt;扩散模型&lt;/strong&gt; ，对于G使用 $c^{k+1}(v)=HASH({c^k(v),{c^k(u)_{u\in neighbor}}})$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其核心是对于开始每个点都为1，而从&lt;strong&gt;图上点的信息可以进行传播&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;以上介绍了node,link,graph的常见特征设计思路，可以发现，使用&lt;strong&gt;距离，degree，子图，扩散模型&lt;/strong&gt; 等思路，都可以设计出比较合适的特征，而这些特征设计思路在之后的GNN设计中也会有所体现&lt;/p&gt;</content:encoded><h:img src="/_astro/background.CPbbDKQL.jpg"/><enclosure url="/_astro/background.CPbbDKQL.jpg"/></item><item><title>CS229：优化理论（一）——数据预处理与基本模型优化方法</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-opt-th-1-data-preproc/cs229-opt-th-1-data-preproc</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-opt-th-1-data-preproc/cs229-opt-th-1-data-preproc</guid><description>CS229：优化理论（一）——数据预处理与基本模型优化方法</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;之前我们学习了若干种模型，我们可以去训练这些模型，但是在得出一个结果之后，我们该如何分析这些结果，并尝试进行优化呢？&lt;/p&gt;
&lt;p&gt;在Lecture9,10,13中，我们就学习了解决这个问题的基本方法，Andrew Ng介绍了数据处理与分配的方法，并介绍了若干种分析优化模型的观点：&lt;/p&gt;
&lt;p&gt;调整优化方法：从&lt;strong&gt;几何直观，数学推导&lt;/strong&gt; 的角度介绍了分析模型的&lt;strong&gt;bias 和variance&lt;/strong&gt; 的方法，并且将其应用到对于一个已知模型，使用bias/variance分析去优化他；使用&lt;strong&gt;决策树&lt;/strong&gt; 结合多种machine减小方差（&lt;strong&gt;random forest&lt;/strong&gt; ）并使用若干种方法调整其中的权重（&lt;strong&gt;boosting method&lt;/strong&gt; ）；&lt;/p&gt;
&lt;p&gt;错误分析：ablative analysis&lt;/p&gt;
&lt;h2&gt;数据分配与处理&lt;/h2&gt;
&lt;p&gt;训练之前，首先需要把数据给准备好，这就包括选择什么作为feature输入以及相应的output,以及怎么对于数据进行分配。&lt;/p&gt;
&lt;h3&gt;数据处理：特征选择&lt;/h3&gt;
&lt;p&gt;对于我们采集到的数据，有  $(x_1,x_2...x_n)^m$  为采集到的数据，但是我们该如何选择采集到的数据作为模型的输入会影响到数据输入的&lt;strong&gt;时间&lt;/strong&gt; （对于数据量过大会影响batch的大小，进而影响到效率与结果），以及&lt;strong&gt;过拟合&lt;/strong&gt; 的程度。&lt;/p&gt;
&lt;p&gt;因此选择所需要的feature的时候可以采用以下的feature-selection method: &lt;strong&gt;Forward-Search&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;** Forward-Search 步骤：**&lt;/p&gt;
&lt;p&gt;对于待放入的特征集合  $F=\phi$  ,以及待选择的特征  $x_1,x_2,...x_n$&lt;/p&gt;
&lt;p&gt;(1)分别使用  $x_1,x_2,...x_n$  来作为模型的输入，并对模型进行评估，选择其中表现最好的，并加入到F中&lt;/p&gt;
&lt;p&gt;(2)从剩余的特征中，考虑  $F+x_1,F+x_2,...F+x_n$  作为模型的输入，再次选出表现最好的，加入到F中&lt;/p&gt;
&lt;p&gt;(3)知道再次操作的时候，若F的正确率比任何的  $F+x_i$  都要好，或者  $F+x_i$  对于正确率的提升不够明显的时候，停止操作。&lt;/p&gt;
&lt;h3&gt;数据分配&lt;/h3&gt;
&lt;p&gt;我们之前在进行训练时会发现一般会有train_dataset，test_dataset以及valid_dataset，其定义是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;train_dataset&lt;/strong&gt; :使用该类数据集中的东西去训练一个模型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;valid_dataset&lt;/strong&gt; :通过比较不同模型在该数据集上面的正确率，对于不同的模型进行评价。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;test_dataset&lt;/strong&gt; :对于选中的模型。得出该模型在该数据集上的正确率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于有一堆的数据进行分配的时候，需要坚持：train，valid,test数据集两两不相交，否则就会将在正确率上有一定的影响，以下是一些常见的分配方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当数据量比较大的时候：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般而言是按照60%，20%，20%&lt;strong&gt;随机&lt;/strong&gt; 分配（random shuffle）分配给train,valid，test上面。&lt;/p&gt;
&lt;p&gt;但是这个比例也不是一定的，如果对于模型比较的时候，若不同模型之间的正确率差距较大（到了1%，2%）的时候，可以适当降低valid_dataset的比例并提高train_dataset的比例，而反之，如果不同模型之间的正确率差异较小，会增大valid_dataset。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当数据量较小的时候：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有的时候对于像医学领域的数据采集，可能没有办法采集到大量的数据，而如果按照以上的方法，对于valid,test数据集都被浪费了，因此我们采用改进的方法：&lt;strong&gt;k折交叉检验&lt;/strong&gt; （k-fold cross validation)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;k-fold cross validation步骤：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(1)将数据集均匀的划分为k份&lt;/p&gt;
&lt;p&gt;(2)对于每一次，取k份数据中的一份作为valid_dataset，其余作为train_dataset，进行训练，求得所有模型响应的正确率&lt;/p&gt;
&lt;p&gt;(3)最后求得模型对于每一个数据集的正确率的均值，并进行比较。&lt;/p&gt;
&lt;p&gt;以上的方法可以较为高效的利用数据，但是相应的** 训练时间会比较的长**。且最好在数据量比较小的时候使用。常见的k我们取10&lt;/p&gt;
&lt;h2&gt;模型优化诊断1：bias/variance 分析&lt;/h2&gt;
&lt;h3&gt;定义及不同角度理解&lt;/h3&gt;
&lt;p&gt;对于一个模型的bias 和variance, ** 定义**为：对于一个数据集  $X=(x_1,x_2,...x_n)$  ,  $bias=E(Y-h_{\theta}(X))$  ,而variance定于为  $var=E((Y-E(Y))^2)$&lt;/p&gt;
&lt;p&gt;而在图像上来看就是对于给定的一组训练数据，通过某种算法得到了一个响应函数，响应函数对应的曲线和真实的数据的差距可以看成是bias,而如果稍微改变一点训练数据集就会导致variance改变巨大，那么可以看成是该模型有High variance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;bias/variance&lt;/p&gt;
&lt;p&gt;从几何的角度去理解，即为对于训练数据训练出的模型对应坐标系中的一个点  $X_i$  ，对于每一组训练数据产生的模型构成在坐标系中的一个圆  $X_1,X_2,...X_n \in O$  （或者高维情况下的类似东西）。而实际上的最佳的模型对应坐标系中的一个点T， 如果对于high bias就说明** 圆  $O$  的圆心和点  $T$  的差距较大**，而对于high variance就是圆  $O$  的** 半径较大**。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;bias/variance&lt;/p&gt;
&lt;p&gt;对于欠拟合：训练模型没有从数据集中得到足够多的信息，导致f(x)与y之间的差距较大。&lt;/p&gt;
&lt;p&gt;过拟合：训练模型与数据集的关系过于紧密，导致训练数据发生微小变化，模型参数就有巨大的变化。&lt;/p&gt;
&lt;p&gt;** 直观上，**如果一个模型有较大的bias，说明该模型还需要更多的训练，即为欠拟合，而响应的，如果有较大的variance，比如使用100次的函数去拟合线性模型，显然会导致过拟合。&lt;/p&gt;
&lt;p&gt;** 理论上，**我们评价一个模型，由于要包含欠拟合与过拟合两者，考虑&lt;/p&gt;
&lt;p&gt;$Test=E((y-\hat{f}(x))^2),y=f(x)+\epsilon$  其中  $\epsilon$  为n元正态分布且  $\Sigma=kI_n$  ，则若模型为过/欠拟合则Test值越大。因此有  $Test =E((f(x)-\hat{f}(x)+\epsilon)^2)\ =E(\epsilon^2)+E(\epsilon)E (f(x)-\hat{f}(x)))+E((f(x)-\hat{f}(x))^2)\ =\sigma^2+E^2(f(x)-\hat{f}(x))+Var(f(x)-\hat{f}(x))\ =\sigma^2+Bias^2+Var$&lt;/p&gt;
&lt;p&gt;因此对于当bias较大的时候，有Test较大，故为欠拟合，同理，Variance较大的时候，为过拟合&lt;/p&gt;
&lt;p&gt;从而有以下结论&lt;/p&gt;
&lt;p&gt;$\textbf{High}\ \textbf{Bias} \Leftrightarrow \textbf{underfitting}\ \textbf{High}\ \textbf{Variance} \Leftrightarrow \textbf{overfitting}\$&lt;/p&gt;
&lt;h3&gt;数据分析&lt;/h3&gt;
&lt;p&gt;接下来我们将会通过** 数据/正确率的曲线图**去分析该模型是过拟合还是欠拟合。&lt;/p&gt;
&lt;p&gt;对于过拟合的模型，由于过拟合，在训练数据集上表现过于优秀，而响应的提取了过多的训练数据的信息，测试数据集有一定的变化，导致正确率比较差。因此对于数据量增大，过拟合趋势会减小，从而其训练数据集正确率下降，而测试数据集正确率上升。&lt;/p&gt;
&lt;p&gt;对于欠拟合模型，欠拟合在会中训练数据和测试数据集的表现差不多，但是总体和较好的模型有一定的正确率差距。从而对于数据量增大，欠拟合并不会改变其“bias”的大小，从而有整体正确率变化不大。&lt;/p&gt;
&lt;p&gt;因此对于一个模型，如果发现** 随着数据量增大，训练数据集和测试数据集的正确率均有较大的变化，则为过拟合，反之为欠拟合**。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;underfitting &amp;#x26; overfitting&lt;/p&gt;
&lt;h3&gt;常见解决方法&lt;/h3&gt;
&lt;p&gt;对于模型出现了过拟合的情况，我们会使用一个叫** 正则化**的东西来减缓过拟合的趋势&lt;/p&gt;
&lt;p&gt;** 正则化：**对于模型损失函数为  $J(\theta)$  ,考虑新的损失函数  $J&apos;(\theta)=J(\theta)+\lambda||\theta||^k$  ，称之为  $L_k$  正则化。&lt;/p&gt;
&lt;p&gt;可以理解为将模型的参数的大小加入到损失函数的考虑范围内。而随着  $\lambda$  的增加，当  $\lambda$  接近0的时候，就还是原来的模型，因此过拟合的模型还是过拟合。而对于  $\lambda$  非常大的时候，损失函数会把  $\theta$  会被拟合成0,此时会变成欠拟合，从而** 对于  $\lambda$  /model complexity曲线**为&lt;/p&gt;
&lt;p&gt;因此使用** bias/variance分析**来解决模型：&lt;/p&gt;
&lt;p&gt;** Step 1.**首先根据模型在训练和测试数据集上的表现判断是过拟合还是欠拟合&lt;/p&gt;
&lt;p&gt;** Step 2.**过拟合：（1）增大数据量 （2）正则化 （3）减少输入数据的维数 （4）使用其余的模型&lt;/p&gt;
&lt;p&gt;欠拟合：（1）加大数据的维数（2）训练更多个周期 （3）使用别的模型&lt;/p&gt;
&lt;h2&gt;模型优化诊断：不同模型的比较与融合&lt;/h2&gt;
&lt;p&gt;对于实际应用模型分析的时候，模型的正确率与训练所花费的时间都是需要考虑的因素，因此我们会考虑将不同的模型融合起来综合考虑，或者通过不同的模型之间的比较来改进自己的模型&lt;/p&gt;
&lt;h3&gt;改进算法：Ensembling Method(决策树，随机森林，boosting提升法)&lt;/h3&gt;
&lt;p&gt;由于篇幅限制，这一块将会留到下一篇文章写。但总结而言，就是** 将不同的模型通过不同的方式进行结合**&lt;/p&gt;
&lt;h3&gt;改进损失函数：比较法（comparison)&lt;/h3&gt;
&lt;p&gt;有的时候，模型的问题在于没有选择效果更好的损失函数（毕竟对于机器学习种的每一个模型都是根据我们的假设产生的）。因此改进损失函数也是比较重要的方法，结合训练时间也是需要重点考量的因素，我们可以使用比较的方法来修改我们的损失函数。&lt;/p&gt;
&lt;p&gt;举个例子：在对于邮件进行分类的时候（spam or not spam）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用Bayes Model:对于spam错误律为2%，not spam错误率为2%（显然太高了）&lt;/li&gt;
&lt;li&gt;使用SVM:对于spam错误率为10%，not soam错误率0.0001%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们需要使用函数  $a(\theta)=\Sigma^m_{i=1} w^i 1{h_{\theta}(x^i)=y^i}$  来评估不同模型的正确率(不同的权重是因为我们希望将所有的not spam的邮件留下)。同时又希望使用Bayes Model(时间快）,但是SVM的效果更好，因此理论上我们有&lt;/p&gt;
&lt;p&gt;$a(\theta_{SVM})&gt;a(\theta_{BLR})$&lt;/p&gt;
&lt;p&gt;对于改进之后的损失函数  $J(\theta)=\Sigma^m_{i=1} log(w^ip(y^i|x_i,\theta))-\lambda ||\theta||^2$  ，对于SVM在这个模型上训练得到的参数为  $\theta_{SVM}$  以及我们使用  $BLR$  训练得到的数据  $\theta_{BLR}$&lt;/p&gt;
&lt;p&gt;如果有  $J(\theta_{SVM})&gt;J(\theta_{BLR})$  那么就可以认为这个损失函数是比较有效的。&lt;/p&gt;
&lt;p&gt;使用以上的方法可以大体的判断我们的改进后损失函数的效果，并由整体趋势判断我们的损失函数应该如何调整。&lt;/p&gt;
&lt;h2&gt;错误分析：ablative analysis&lt;/h2&gt;
&lt;p&gt;对于使用了  $x_1,x_2,...x_n$  有了n个feature的输入，我们需要找到那个feature对结果的影响最大，并在此方面进行改进。这就需要使用到ablative analysis.&lt;/p&gt;
&lt;p&gt;ablative analysis步骤：&lt;/p&gt;
&lt;p&gt;（1）对于  $x_1,x_2,...x_n$  作为模型的输入，得到一个正确率&lt;/p&gt;
&lt;p&gt;（2）依次除去  $x_1,x_2,...x_n$ 中的一个变量，分别进行训练，得到相应的正确率&lt;/p&gt;
&lt;p&gt;（3）根据以上n个正确率与原本的正确率比较得到结论那个变量的影响最大。&lt;/p&gt;
&lt;p&gt;通过以上的分析我们可以对于数据结果进行进一步的分析。&lt;/p&gt;
&lt;p&gt;以上是我们对于模型训练中的常见的步骤，包括数据的预处理部分，对于模型优化，我们需要使用多种方法，包括bias/variance分析，改进算法，改进损失函数，同时对于模型最后的结果我们也可以由此进行分析。&lt;/p&gt;
&lt;p&gt;虽然如此，对于改进模型不能只用以上的方法，更多的方法需要借助于前沿论文研究去考虑，但是对于初步的研究的时候，我们可以从这些方面进行考虑，对于我们的模型进行优化。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:优化理论（二）——决策树与模型优化，数据量估计</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-opt-th-2-decision-trees/cs229-opt-th-2-decision-trees</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-opt-th-2-decision-trees/cs229-opt-th-2-decision-trees</guid><description>CS229:优化理论（二）——决策树与模型优化，数据量估计</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在上一篇文章中，我们介绍了关于数据处理，模型优化的一些基本方法。而接下来接下来我们将会借由决策树这一工具介绍将多种模型融合在一起的方法:集成方法，同时介绍一些关于数据量选取的基本方法。&lt;/p&gt;
&lt;h2&gt;决策树（Decision Tree）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;场景：&lt;/strong&gt; 考虑我们要将从（1-12月，纬度）作为输入与是否可以滑雪作为输出的一个散点图进行分类。则其图像如下。要对此进行分类显然可以使用SVM去考虑，但是介于训练时间的缘故，为了解决这种非线性边界的问题，使用一种叫决策树的结构去实现一个分类器。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Decision Tree Presenting&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;决策树实现过程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;** Step1**:对于每一个包含n个feature的数据  $x^i=(x^i_1,x^i_2,...x^i_n),i\in [1,n]$  ，设置一个Selecting Region, 记为  $N_1={conditions  \ on \ x_i,i\in[1,m]}$  其中条件为对于每一个feature在边界上的一些限制。&lt;/p&gt;
&lt;p&gt;比如  $N_1={x_1&gt;10,x_2&gt;0.1}$&lt;/p&gt;
&lt;p&gt;** Step2:**对于训练数据而言，将满足N1条件的数据作为左侧节点的输入，不满足的作为右侧节点的输入。以此类推，对于左右侧的节点分别进行同理的分类操作。直到分类分到叶子节点。&lt;/p&gt;
&lt;p&gt;** Step3:**当希望对于某个数据进行预测的话，再根节点处进行判断，如果符合  $N_1$  条件，则传入左侧节点进行预测，反之传入右侧节点进行预测。直到叶节点，最终的预测情况根据叶子节点的预测的均值作为最后的输出。&lt;/p&gt;
&lt;p&gt;图形解释见下图。由于每一个节点存储了分类条件，以及与左右节点之间的联系，因此称为决策树。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Decision Tree&lt;/p&gt;
&lt;p&gt;我们以及知道了决策树的原理，只需要直到如何得到每一个节点的Selecting Region就能得到一个分类器，实际情况中，如果对于每一个点的Selecting Region涉及到了过多的feature的时候，一方面会有训练时间复杂度上升，另一方面会导致严重的过拟合，因此我们默认对于每个节点只对于一个feature进行分类了。&lt;/p&gt;
&lt;p&gt;** 损失函数**&lt;/p&gt;
&lt;p&gt;需要训练模型，必然需要一个损失函数。我们考虑这是一个二分类器&lt;/p&gt;
&lt;p&gt;我们的原则是希望在每一次分类的过程中，分出来的两类的希望可以将标签为1和0的东西分别归成两类，因此评判标准应当为两类中的正确率。结合过往在逻辑回归的经历，我们记对于Selecting Region  $N$  的正确率为  $p_N=\dfrac{\Sigma1{y^i=1,y^i\in N}}{\Sigma1{y^i\in N}}$  ,对于其分成了两个子类  $N_1,N_2$  ,损失函数为  $L_{cross}:Loss_N=-(p_{N_1}log(p_{N_1})+p_{N_2}log(p_{N_2}))$&lt;/p&gt;
&lt;p&gt;结合图像发现，只要对于  $p_{N_1},p_{N_2}$  相隔更远，那么损失函数的值就应该更小，这符合凸函数的特点，因此理论上对于任何的凸函数我们都应该成立，类似的还有一些别的常见的损失函数&lt;/p&gt;
&lt;p&gt;$L_{mini}:Loss=p_{N_1}(1-p_{N_1})+p_{N_2}(1-p_{N_2})$&lt;/p&gt;
&lt;p&gt;训练模型时，我们递归对于每个节点划定其边界（二分范围知道继续划分正确率不再改变），通过损失函数确定每一个点的Selecting Region,直到所有节点确定。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Loss Function&lt;/p&gt;
&lt;h3&gt;正则化&lt;/h3&gt;
&lt;p&gt;举个例子，如果边界是分块的，如左图，那么Decision Tree的表现会非常好，反之，对于一个线性拟合的模型,如右图，那么Decision Tree就会有较强的过拟合，因此就需要进行正则化减小过拟合。&lt;/p&gt;
&lt;p&gt;常见的正则化方法有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设定叶子节点的最小大小&lt;/li&gt;
&lt;li&gt;设定最深的深度，在到达一定的深度时停止分类&lt;/li&gt;
&lt;li&gt;设定节点的最大的个数&lt;/li&gt;
&lt;li&gt;后剪枝方法：用验证集来评估每个节点的错误率，若将该节点的子节点后正确率上升，那么进行剪枝，时间复杂度:设验证集大小N,测试集合大小为n，f个feature,树深为  $O(logn)$  ,后剪枝的时间复杂度为  $O(Nf(logn)^2)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;集成化方法（Ensembling Methods）&lt;/h2&gt;
&lt;h3&gt;Bagging&lt;/h3&gt;
&lt;p&gt;基于  $Var(\hat{X})=\dfrac{Var(X)}{n}$  ,我们可以考虑将若干个不同的模型组合起来减小模型的过拟合趋势，方法为将数据集分成n份，对于每一个数据集训练出来一个单独的模型，对于需要预测的数据，我们取&lt;strong&gt;所有模型结果的平均&lt;/strong&gt; 。该过程称为&lt;strong&gt;Bagging（Variance Reduction）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;** Random Forest:&lt;strong&gt;由于决策树的过拟合情况严重，使用bagging可以大大&lt;/strong&gt; 减小过拟合**，Bagging+Decision Tree就是随机森林（只是对于每一个决策树的特征选取上是使用M个特征中的m个），但是这样做的缺点是失去了每一颗决策树的** 可解释性**。&lt;/p&gt;
&lt;h3&gt;Boosting&lt;/h3&gt;
&lt;p&gt;以上都是为了减少过拟合，但是我们也需要减少bias,这就需要使用boosting&lt;/p&gt;
&lt;p&gt;** 核心思想：**通过训练弱分类器，找到其分错的样本，提高这些被错误分类样本的权重，在加权后的数据上训练下一个弱分类器最后将所有分类器的加权结果组合成一个强分类器（类似于强化学习的思想）。优点为减小bias,但是会增加Variance.&lt;/p&gt;
&lt;p&gt;常见的算法有Adaboost(改变每样本的权重),FSAModeling(每次改变添加新的tree stump的比例),Gradient Boosting等，这些都有相应的python库且都有一定的应用。&lt;/p&gt;
&lt;p&gt;以上我们这篇文章我们从决策树出发，聊到了 Bagging 和 Boosting，这是两种改进模型性能的常见方法，一个降低方差，一个减少偏差，互为补充。将这些方法与上篇文章相结合，必定会有更优良的效果。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229: Ps0解读——矩阵求导与重要矩阵性质</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps0-mat-deriv-properties/cs229-ps0-mat-deriv-properties</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps0-mat-deriv-properties/cs229-ps0-mat-deriv-properties</guid><description>CS229: Ps0解读——矩阵求导与重要矩阵性质</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS229的作业的设置只能用&lt;strong&gt;贴合实际，变化丰富，质量极高&lt;/strong&gt; 来形容。包含对于课堂上某些提到的性质，推论的证明与拓展，也有非常多的实践项目，更重要的是，有很多有趣的题目竟然可以将好几个lecture内的知识点穿起来，实在是巧妙至极。&lt;/p&gt;
&lt;p&gt;以下答案中可能有错，欢迎大家指正&lt;/p&gt;
&lt;h2&gt;Problem Set 0 解读:&lt;/h2&gt;
&lt;h3&gt;problem 1&lt;/h3&gt;
&lt;p&gt;1.Problem:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Problem 1&lt;/p&gt;
&lt;p&gt;2.分析：&lt;/p&gt;
&lt;p&gt;这道题目主要是练习矩阵求导的技巧，(a),(c)可以说是对于Linear Regression中的损失函数  $J(\theta)=\frac{1}{2}(y-\theta^Tx)^T (y-\theta^Tx)$  求导的一个证明，而对于（b),(d)是对于Logistic Regression的损失函数的一个证明，总结下来，对于矩阵求导（一般是对于一个向量）需要掌握以下：&lt;/p&gt;
&lt;p&gt;对于  $\textbf{x}= \begin{bmatrix} x_1,x_2,x_3,...x_n \end{bmatrix}^T$  而言，  $f(\textbf{x})$  为  $R^n\rightarrow R$  的函数，则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向量求导定义： $\dfrac{\partial f(\textbf{x})}{\partial \textbf{x}}=[\dfrac{\partial f(\textbf{x})}{\partial x_1},\dfrac{\partial f(\textbf{x})}{\partial x_2}...\dfrac{\partial f(\textbf{x})}{\partial x_n}]^T$&lt;/li&gt;
&lt;li&gt;分配律：  $\dfrac{\partial f(\textbf{x})g(\textbf{x})}{\partial\textbf{x}}=\dfrac{\partial f(\textbf x)}{\partial \textbf x } g(\textbf{x})+f(\textbf{x})\dfrac{\partial g(\textbf x)}{\partial \textbf x } $&lt;/li&gt;
&lt;li&gt;线性映射求导：  $\dfrac{\partial \textbf{a}^T\textbf{x}}{\partial \textbf{x}}=\dfrac{\partial \textbf{x}^T\textbf{a}}{\partial \textbf{x}}=\textbf{a}$  (证明由定义易证）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由以上的定理(分配律+线性映射)可以得到以下的结论&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结论1：  $\dfrac{\partial \textbf{a}^T\textbf{x}\textbf{x}^T\textbf{b}}{\partial \textbf{x}}=\textbf{ab}^T\textbf{x}+\textbf{ba}^T\textbf{x}$&lt;/li&gt;
&lt;li&gt;结论2：  $\dfrac{\partial \textbf{x}^T\textbf{A}\textbf{x}}{\partial \textbf{x}}=\textbf{A}\textbf{x}+\textbf{A}^T\textbf{x}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上是一些常见的结论，对于更多的关于矩阵求导的内容可以参考这篇文章&lt;/p&gt;
&lt;p&gt;使用以上的结论就可以轻松解决Problem 1&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Problem 1 answer(可能有错，欢迎指正)&lt;/p&gt;
&lt;h3&gt;problem 2&lt;/h3&gt;
&lt;p&gt;Problem&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem&lt;/p&gt;
&lt;p&gt;分析：&lt;/p&gt;
&lt;p&gt;在机器学习中我们常常使用使用到&lt;strong&gt;正定矩阵&lt;/strong&gt; 这个东西，像之后几个lecture中的GLM中常常使用的损失函数，以及在决策树中会使用到的损失函数，都和这个正定矩阵的性质有关。因此接下来我们来总结以下对于正定矩阵的性质。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正定矩阵定义：A为正定矩阵，若对于任意的  $\textbf{x}= \begin{bmatrix} x_1,x_2,x_3,...x_n \end{bmatrix}^T$  ，有  $\textbf{x}^T A \textbf{x}&gt;0$  恒成立&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$\Leftrightarrow X^T AX&gt;0 $  ，其中  $X$  为任意的正交矩阵（使用一个正交变换，通过实二次型即可）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正定矩阵：正定矩阵的顺序主子式均大于0，特征值都是正的（证明见USTC线性代数的课件）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用以上的性质，我们在分析任意的关于&lt;strong&gt;函数的凸性，或者求解损失函数的偏导&lt;/strong&gt; 的相关性质（如对于Hessian矩阵的性质）使用正交变换将x向量转换成基向量，再使用正定矩阵的性质去分析。&lt;/p&gt;
&lt;p&gt;从而我们可以轻松得到以下答案&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Solution to problem 2&lt;/p&gt;
&lt;h3&gt;problem 3&lt;/h3&gt;
&lt;p&gt;problem&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem&lt;/p&gt;
&lt;p&gt;对于这个题目主要是对于&lt;strong&gt;正交矩阵&lt;/strong&gt; 的性质进行了探讨。对于正交矩阵的最为重要的特点是他保内积，可以将一个欧式空间直接投影到欧式空间中，在training_input上来看就是将输入转换成了一组基的问题。&lt;/p&gt;
&lt;p&gt;对于正交矩阵我们常用的特点有以下几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义：对于A为正交矩阵，则有  $\textbf{A}^T\textbf{A}=I$&lt;/li&gt;
&lt;li&gt;性质1：A的特征值的模长都是1，而且对于复根组成的2*2的矩阵与别的实特征值可以组成一个Jordan标准型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性质2&lt;/strong&gt; ：对于B为一个对称矩阵，则B正交相似于一个对角矩阵。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PS0是为了之后的学习中的各种证明打下了一个比较坚实的基础，包括矩阵求导以及最为重要的两类特殊矩阵的性质。有了他们，之后完成PS1,PS2...就更加容易了。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229：Ps1解读——GLM模型及其变种的编程实现与相关性质证明</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps1-glm-models-impl/cs229-ps1-glm-models-impl</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps1-glm-models-impl/cs229-ps1-glm-models-impl</guid><description>CS229：Ps1解读——GLM模型及其变种的编程实现与相关性质证明</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS229的前4个lecture讲解了GLM模型，而problem set 1是实现了GLM中的常见的模型：GDA模型，Newton方法，数据集不完整的标签的情况，泊松分布作为GLM模型中的exponential function的离散情况的预测,exponential family的凸性，自权重线性回归模型。若干个题目恰好对应了Lecture中的重要的知识点。下面是我做这些题目的心得体会。&lt;/p&gt;
&lt;h2&gt;Problem Set 1 解析&lt;/h2&gt;
&lt;h3&gt;Problem 1&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Problem 1&lt;/p&gt;
&lt;p&gt;分析：&lt;/p&gt;
&lt;p&gt;这道题目是为了说明GDA是一种特殊的逻辑回归，并且对于损失函数的可行性 (损失函数  $J(\theta)$  是凸函数)进行了证明，并使用了牛顿法对于GDA进行了实现。&lt;/p&gt;
&lt;p&gt;（a)这一问需要证明交叉熵函数是凸的，在定义域范围内只有一个极值点，从而无论初始值取多少，最后都可以使用梯度下降到所需要的点，而需要证明这等价与&lt;strong&gt;损失函数的Hessian矩阵是正定矩阵&lt;/strong&gt; 。使用上一篇文章中的结论，我们可以进行求解。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Problem 1/(a)&lt;/p&gt;
&lt;p&gt;这一个题目中，可以发现sigmoid函数的一个特殊性质：  $f(x)=sigmoid(x)\Rightarrow f&apos;(\textbf{X})=f(\textbf{X})*(1-f(\textbf{X}))$  这里的*是按照元素相乘。（&lt;strong&gt;在之后的训练中非常的有用&lt;/strong&gt; ）&lt;/p&gt;
&lt;p&gt;（c,d)对于（c),我们是使用了Bayes Rules，结合了对于Gaussian假设证明了GDA模型可以化简为逻辑回归，间接说明了生成式回归实际上需要再加上&lt;strong&gt;可靠的假设可以化为逻辑回归&lt;/strong&gt; 。而对于（d)，我们对于GDA求其最大似然估计，再进行求导，就得到了GDA参数的表达式，（d)说明了在分析一个问题的时候可以&lt;strong&gt;使用GDA来快速对于数据进行初步分析。&lt;/strong&gt; 这两问的证明都是暴力计算。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;（b，e）编程题，这两个问题实现了Newton法的梯度下降以及GDA预测数据。我在编写这些代码中，发现有些debug中较为易错的点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在计算Hessian矩阵的时候，我们需要注意sigmoid函数求导之后为了保证维数相同，对于输入矩阵A，按元素相乘到x上。（注意维数）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Hessian=(x.T*(1-hypothesis)*hypothesis).dot(x)/m
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;由于输入x不像习惯中的列向量组成  $X=(x_1,x_2,....x_n)$  ,在numpy中是将每一行视为一个输入，因此在计算  $\theta^T X$  时不需要使用转置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;W=x.dot(theta)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后关键代码如下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
class LogisticRegression(LinearModel):
    def fit(self, x, y):
        &quot;&quot;&quot;Run Newton&apos;s Method to minimize J(theta) for logistic regression.
        Args:
            x: Training example inputs. Shape (m, n).
            y: Training example labels. Shape (m,).
        &quot;&quot;&quot;
        self.theta=np.zeros(x.shape[1])# 参数初始化
        m,n=x.shape
        while True :
            hypothesis=1/(1+np.exp(-x.dot(self.theta)))#对于输入计算sigmoid输出
            Hessian=(x.T*hypothesis*(1-hypothesis)).dot(x)/m#Hessian矩阵
            gradient_descent=x.T.dot(hypothesis-y)/m#计算梯度下降
            theta_old=np.copy(self.theta)
            self.theta-=np.linalg.inv(Hessian).dot(gradient_descent)#梯度下降
            #ord refers to L1 or L2 
            if  np.linalg.norm(self.theta-theta_old,ord=1) &amp;#x3C;self.eps:#判断结束L1条件
                break
    def predict(self, x):
        hypothesis=1/(1+np.exp(-x.dot(self.theta)))
        y=[1 if q&gt;0.5 else 0 for q in hypothesis]#判断条件
        return y

#GDA Predictions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GDA中注意使用numpy操作，以下是计算参数的代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        phi=np.sum(y)/m

        mu_0=((1-y).dot(x))/(np.sum(1-y))
        mu_1=(y.dot(x))/(np.sum(y))
        # calculas \sigma
        sigma=np.zeros((2,2))
       # print((x[0]-mu_0).T)
        for i in range(m):
            if y[i]==0:
                sigma+=(np.array([x[i]-mu_0])).T.dot(np.array([x[i]-mu_0]))
            else:
                sigma+=(np.array([x[i]-mu_1])).T.dot(np.array([x[i]-mu_1]))
        sigma=sigma/m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 2&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Problem 2&lt;/p&gt;
&lt;p&gt;在日常的使用的时候，我们常常会遇到只有部分标签的问题。而这道问题则是证明了使用标签过后的数据来训练模型在实际的预测中是合理的，假设（  $y^i,x^i,t^i$  ）分别表示数据是否被标签，数据内容以及数据真实情况下的分类情况。而其方法就是将&lt;strong&gt;分类情况预测转换成对于标签情况的判定&lt;/strong&gt; 。从而可以利用上我们的训练数据。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 2 solution&lt;/p&gt;
&lt;p&gt;在（a)通过假设了一组数据是否标签与其预测值为是还是否无关（y,x与t条件独立），证明了数据的分类情况与其标签与否成比例关系。由于对于标签情况我们是知道的，于是就可以将对于分类的预测转换成数据是否标签的预测。(使用概率统计公式进行变换)&lt;/p&gt;
&lt;p&gt;具体实现主要部分：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    hypothesis=1/(1+np.exp(-x_valid_new.dot(clf.theta)))
    num_V_positive=np.sum(y_valid_new[y_valid_new==1])
    hypothesis_V_positive=np.sum(hypothesis[y_valid_new==1])
    alpha=hypothesis_V_positive/num_V_positive
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 3&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 3&lt;/p&gt;
&lt;p&gt;对于&lt;strong&gt;Gaussian分布&lt;/strong&gt; ，我们可以对实数轴上的东西进行预测（Linear Regression),而对于&lt;strong&gt;伯努利分布&lt;/strong&gt; ，可以实现一个分类器，如果我们想要将数据分类到离散的整数上，就可以使用泊松分布。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 3 solution&lt;/p&gt;
&lt;p&gt;在（a)中我们先进行基本变换将其变换成exponential family的形式，（b，c)中则使用P(y|x,params)~exponential family的性质得到响应函数以及损失函数的形式，最后再实现这个代码。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class PoissonRegression(LinearModel):
    &quot;&quot;&quot;Poisson Regression.
    Example usage:
        &gt; clf = PoissonRegression(step_size=lr)
        &gt; clf.fit(x_train, y_train)
        &gt; clf.predict(x_eval)
    &quot;&quot;&quot;
    def fit(self, x, y):
        &quot;&quot;&quot;Run gradient ascent to maximize likelihood for Poisson regression.

        Args:
            x: Training example inputs. Shape (m, n).
            y: Training example labels. Shape (m,).
        &quot;&quot;&quot;
        # *** START CODE HERE ***
        self.theta=np.zeros(x.shape[1])
        print(x[0].T.shape)
        print(y.shape)
        print(self.theta.shape)
        while True:
            theta_old=np.copy(self.theta)
            self.theta=self.theta+self.step_size*x.T.dot(y-np.exp(x.dot(self.theta.T)))/x.shape[0]
            if np.linalg.norm(self.theta-theta_old,ord=1)&amp;#x3C;self.eps:
                break
            # pay attention to devide the shape of
        # *** END CODE HERE ***
    def predict(self, x):
        # *** START CODE HERE ***
        hypothesis=np.round(np.exp(x.dot(self.theta.T)))
        return hypothesis
        # *** END CODE HERE ***
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Problem 4&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_08.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 4&lt;/p&gt;
&lt;p&gt;我们为何使用GLM模型，有非常大的原因是因为其** 独特的凸性**。而本题中，（a)证明了对于预测函数的均值可以表示为损失函数对于参数的导数，而（b)则证明了预测函数的方差可以看成损失函数对于参数的二阶导。从而可以由方差的性质证明损失函数的凸性。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_09.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 4 solution&lt;/p&gt;
&lt;p&gt;于是我们使用** 积分变换**就可以证明该性质，最后利用正定矩阵就可以证明凸性。具体见过程&lt;/p&gt;
&lt;h3&gt;Problem 5&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_10.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 5&lt;/p&gt;
&lt;p&gt;上课的时候我们只是描述了自权重回归的模型，但是对于其在梯度，** 一般情况下的normal equation并没有特别的研究。**因此本题中对于一般的  $J(\theta)=\frac{1}{2}\Sigma^m_{i=1}w^i(y^i-\theta^Tx^i)^2$  得到了通解  $\theta = (X^T W X)^{-1} X^T W y$  ，并对于权重取Gaussian分布的情况下进行了代码实现。&lt;/p&gt;
&lt;p&gt;以及其过程&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_11.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;problem 5 solution&lt;/p&gt;
&lt;p&gt;以及相应代码实现，尤其注意对于** 大量矩阵乘法时的维数！！！**&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def predict(self, x):
        m,n=x.shape
        y=np.zeros(m)
        for i in range(m):
            W=np.diag(np.exp(-np.sum((self.x-x[i])** 2,axis=1))/(2*self.tau**2))
            y[i] = np.linalg.inv(self.x.T.dot(W).dot(self.x)).dot(self.x.T).dot(W).dot(self.y).T.dot(x[i])
        return y
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229: Ps2解读——正则化深入探讨以及SVM实现</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps2-reg-svm/cs229-ps2-reg-svm</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps2-reg-svm/cs229-ps2-reg-svm</guid><description>CS229: Ps2解读——正则化深入探讨以及SVM实现</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;整体而言，这份作业是对于&lt;strong&gt;正则化&lt;/strong&gt; 在数据集异常，实际意义，对于正确率影响上进行了深入的探讨，同时在也实现了SVM的部分。&lt;/p&gt;
&lt;p&gt;首先是作业以及作业答案的文档（每一题贴图片粘太麻烦了，开摆了）&lt;/p&gt;
&lt;h2&gt;Problem 1&lt;/h2&gt;
&lt;p&gt;Problem1主要是考察当数据集形状特殊时，如何对于逻辑回归函数进行修改。我们发现，对于逻辑回归，若数据中有&lt;strong&gt;微小的噪声&lt;/strong&gt; ，由于偏离边界的错误分类数据对与参数影响较大，每一个iteration对于参数的惩罚相应较大（Dataset A），从而即使精度会有所下降，但是收敛速率会&lt;strong&gt;大大加快&lt;/strong&gt; 。反之，如果数据中没有噪声，那么收敛速率会相应变慢(Dataset B)。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;A&amp;#x26;B&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Result&lt;/p&gt;
&lt;p&gt;于是我们需要对此，我们训练B数据集的时候，就需要加上一些噪声，而由于是逻辑回归，对于学习率加大，以及正则化都无法帮助我们在训练到100000iteration时快速收敛。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem1 Essence:训练数据决定改进策略&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Problem 2&lt;/h2&gt;
&lt;p&gt;Problem 2主要探讨了一个问题：  $h_{\theta}(x)=\sigma(x)$  实际意义的确是二分类中数据集的正确率&lt;/p&gt;
&lt;p&gt;通过第一问我们首先证明了当偏置项的均值为0时，我们在（0，1）区间上  $acc=\frac{\sum_{i \in I_{a,b}} P(y^{(i)} = 1 \mid x^{(i)}; \theta)}{|{i \in I_{a,b}}|}=\frac{\sum_{i \in I_{a,b}} h_\theta(x)}{|{i \in I_{a,b}}|}$  的确可以作为数据集的准确率。而在第二问中我们是将该情况推广到了任意区间上&lt;/p&gt;
&lt;p&gt;最后当我们加上正则化之后，我们通过理论上的证明发现正则化会导致整体的均值偏差。  $acc=\frac{\sum_{i \in I_{a,b}} P(y^{(i)} = 1 \mid x^{(i)}; \theta)}{|{i \in I_{a,b}}|}=\frac{\sum_{i \in I_{a,b}} h_\theta(x)}{|{i \in I_{a,b}}|}$  与实际的正确率会有所偏差。&lt;/p&gt;
&lt;p&gt;Problem2进一步告诉了我们：** 正则化会带来正确率损失**，所以对于需要高正确率的问题时要谨慎使用。&lt;/p&gt;
&lt;h2&gt;Problem 3&lt;/h2&gt;
&lt;p&gt;之前我们在处理线性回归时，都是通过MLE(最大似然估计)  $\theta_{\text{MLE}} = \arg\max_\theta p(y|x, \theta)$  ，但是如果加上正则项之后，其解释性不是特别的好，因此我们在本题中通过  $\theta_{\text{MAP}} = \arg\max_\theta p(\theta|x, y)$  与MLE之间的联系，最后给予正则化一个合理的实际意义。&lt;/p&gt;
&lt;p&gt;在本题中，(a)告诉了我们MAP就是MLE加上一个分布惩罚项，（b)(c)我们通过假设参数的先验分布（Gaussian,Lasso）验证了不同的正则化在MAP下的等价性。&lt;/p&gt;
&lt;p&gt;Problem3 Essence:** 正则化不是“黑箱”技巧，而是我们对模型参数的主观信念的数学表达**&lt;/p&gt;
&lt;h2&gt;Problem 4&lt;/h2&gt;
&lt;p&gt;简简单单的暴力题目，主要是对于** 核函数的性质**的推导&lt;/p&gt;
&lt;h2&gt;Problem 5&lt;/h2&gt;
&lt;p&gt;实现核函数以及SVM预测，对于每一个数据，我们记录了其xi以及一个变换常数，最后做出预测。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def initial_state():
    state = []
    return state

def predict(state, kernel, x_i):
    sum=0
    for b,x_j in state:
        sum=sum+b*kernel(x_j,x_i)
    prediction=sign(sum)
    return prediction


def update_state(state, kernel, learning_rate, x_i, y_i):
    if state== None:
        b_new=learning_rate*(y_i-predict([(0,x_i)],kernel,x_i))
    else:
        b_new=learning_rate*(y_i-predict(state,kernel,x_i))
    state.append((b_new,x_i))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后的效果图也是非常的好看的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;线性核以及高斯核&lt;/p&gt;
&lt;h2&gt;Problem 6&lt;/h2&gt;
&lt;p&gt;这道题目是通过比较Bayes Model于SVM的正确率去实现一个垃圾邮件分类系统。其中SVM的效果是通过调用上一个题目的部分去实现的。主要的难点还是在维度的控制，文字的预处理上，包括提取词库，完善字典。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_words(message):
    str=message.lower()
    lis=str.split(&apos; &apos;)
    #print(lis)
    return lis

def create_dictionary(messages):
    dictionary={}
    for message in messages:
        transform_message=get_words(message)
        for word in transform_message:
            if word in dictionary.keys():
                dictionary[word]+=1
            else:
                dictionary[word]=1
    remove_keys=[key for key,value in dictionary.items() if value&amp;#x3C;5]
    for key in remove_keys:
        del dictionary[key]
    for i,word in enumerate(dictionary):
        dictionary[word]=i
    return dictionary
def transform_text(messages, word_dictionary):
    transform_matrix=np.zeros((len(messages),len(word_dictionary)), dtype=int)
    print(transform_matrix.shape)
    for i,message in enumerate(messages):
        message_word=get_words(message)
        for word in message_word:
            if word in word_dictionary:
                transform_matrix[i][word_dictionary[word]]+=1
    print(1)
    return transform_matrix

def fit_naive_bayes_model(matrix, labels):
    
    phi_y=labels.sum()/len(labels)
    
    matrix_1=matrix[labels==1]
    matrix_0=matrix[labels==0]
    nominator_1=matrix_1.sum(axis=0)
    denominator_1=matrix_1.sum(axis=1).sum()
    nominator_0=matrix_0.sum(axis=0)
    denominator_0=matrix_0.sum(axis=1).sum()

    phi_1=(nominator_1+1)/(denominator_1+matrix.shape[1])
    phi_0=(nominator_0+1)/(denominator_0+matrix.shape[1])
    return phi_y,phi_1,phi_0
def predict_from_naive_bayes_model(phi_y,phi_1,phi_0, matrix):
    theta=np.log(phi_1)+np.log(1-phi_1)-np.log(1-phi_0)-np.log(phi_0)
    denominator=theta.dot(matrix.T)
    denominator=1/(1+np.exp(denominator)*(1-phi_y)/phi_y)
    predictions=[0 if x&gt;0.5 else 1 for x in denominator]
    return predictions
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229：Ps3解读——NN,自然梯度下降与有趣的案例</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps3-nn-natural-gd/cs229-ps3-nn-natural-gd</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps3-nn-natural-gd/cs229-ps3-nn-natural-gd</guid><description>CS229：Ps3解读——NN,自然梯度下降与有趣的案例</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;problem set3总体是非常有趣的，包括对于神经网络的深层次理解，对于梯度下降在概率流形上的改进——自然梯度下降，以及一些实际的有趣的案例&lt;/p&gt;
&lt;p&gt;对于作业以及作业答案如下&lt;/p&gt;
&lt;h2&gt;Problem 1&lt;/h2&gt;
&lt;p&gt;problem 1是手动实现一个神经网络，包括正向传播于反向传播，但特别是第一问，对于如图的一个数据集合，我们想要使用NN来拟合出来边界&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;（a)中我们需要手动将神经元中的参数给弄出来，我们可以发现三个神经元对应正好三条边界，而又有ReLU这个东西，从而正好我们可以将每一个神经元表示成每一条边界的方程形式，然后通过ReLU将内部分出来。&lt;/p&gt;
&lt;p&gt;（b)则是实现了这个东西。具体的代码如下，更加细节的讨论我们留到cs230去考虑&lt;/p&gt;
&lt;p&gt;Problem 1告诉我们：&lt;strong&gt;神经网络中每一个神经元都可以表示一个特征（数据组成的高维空间中的一个分割的平面）&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;** Problem 2&amp;#x26;Problem 3**&lt;/h2&gt;
&lt;p&gt;这一次的problem set中出的最好的感觉就是这两个题目了。由于无监督学习，尤其是Mixture of Gaussian是假设了概率模型，因此本题目通过信息论的角度讨论了在概率流形上无监督学习的合理性。&lt;/p&gt;
&lt;p&gt;** problem 2**首先介绍了一些信息论的术语&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;概率分布的信息量  $I(P(x))$  :  $I(P(x_i))=-log2(P(x_i))$  即为如果概率越小，那么含有的信息越多。我们生活中，  $2^n$  的星系可以由n个bit去表示，因此-log2还是比较合理的&lt;/li&gt;
&lt;li&gt;熵：  $H(P)=E_{X\sim P(X)}I(P(x))=-\Sigma P(x)log_2(P(x))$  表示如果信息是按照P(x)去分布的，那么平均下来需要多少的“bit”去表示一份信息&lt;/li&gt;
&lt;li&gt;交叉熵：  $H(P,Q)=E_{X\sim P(X)}I(Q(x))=-\Sigma P(x)log_2(Q(x))$  表示使用Q(x)的方式去表示P(x)那么所需要的信息量，实际例子如使用计算机编码去表示语言。&lt;/li&gt;
&lt;li&gt;KL散度  $D_{\text{KL}}(P \parallel Q) = \sum_{x \in \mathcal{X}} P(x) \log \frac{P(x)}{Q(x)}$  ，表示使用Q(x)的方式去表示P(x)那么所多需要的信息量，也可以理解为P(x)于Q(x)之间的“距离”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此我们通过代数操作可以发现  $D_{KL}(P||Q)=H(P,Q)-H(P)$  。&lt;/p&gt;
&lt;p&gt;Problem 2主要是来验证KL散度作为‘距离’的一些性质(经过了大量的数学计算)&lt;/p&gt;
&lt;p&gt;（a)KL散度满足&lt;strong&gt;非负性&lt;/strong&gt;  $\forall P, Q,\ D_{\text{KL}}(P \parallel Q) \geq 0$&lt;/p&gt;
&lt;p&gt;（b)KL散度的** 链式法则**  $D_{\text{KL}}(P(X|Y) \parallel Q(X|Y)) = \sum_y P(y) \left( \sum_x P(x|y) \log \frac{P(x|y)}{Q(x|y)} \right)$  （类似于全概率公式）&lt;/p&gt;
&lt;p&gt;（c)KL散度于MLE:预测模型的概率分布与实际数据的概率分布的KL散度就是MLE,  $\arg\min_{\theta} D_{\text{KL}}(\hat{P} \parallel P_{\theta}) = \arg\max_{\theta} \sum_{i=1}^{n} \log P_{\theta}(x^{(i)})$&lt;/p&gt;
&lt;p&gt;Problem 2说明了KL散度可以作为一个模型的损失函数(非负性=存在最优解，链式法则=已知数据集条件下， MLE=说明与之前情况的等价解释)&lt;/p&gt;
&lt;p&gt;由于之前我们所有的参数优化都是在** 欧式空间&lt;strong&gt;上的优化，而我们需要优化的是参数，需要用信息论上的&lt;/strong&gt; 概率流形&lt;strong&gt;去逼近参数（毕竟我们的评判标准都是选的MLE）,因此我们考虑改变参数对于KL散度的影响=&gt;使用自然梯度下降去逼近参数，&lt;/strong&gt; Problem 3**就做了这件事情&lt;/p&gt;
&lt;p&gt;（a)首先证明了对于KL散度（距离）下，对于理论上的最优分布时，确实值为0（验证距离=0的** 取等条件**）&lt;/p&gt;
&lt;p&gt;（b)，（c)我们使用了Taylor展开，使用Fisher矩阵（ 概率流形下 $\theta$  处的曲率）可以求得对于  $\theta\Rightarrow\theta+d$  时** KL散度的变化**  $D_{\text{KL}}(p_\theta \parallel p_{\theta + d}) \approx \frac{1}{2} d^\top \mathcal{I}(\theta) d$&lt;/p&gt;
&lt;p&gt;（d)中，自然梯度下降的中心是为了保证在** 固定分布变化量下最大化损失**。&lt;/p&gt;
&lt;p&gt;$d^* = \arg\max_d \ell(\theta + d) \quad \text{subject to} \quad D_{\text{KL}}(p_\theta \parallel p_{\theta + d}) = c$  。&lt;/p&gt;
&lt;p&gt;从而我们使用Lagrange Multipliyer,即可得到最后的表达式&lt;/p&gt;
&lt;p&gt;$\theta_{t+1} = \theta_t - \eta , \mathcal{I}(\theta_t)^{-1} \nabla_\theta \mathcal{L}(\theta_t)$&lt;/p&gt;
&lt;h2&gt;Problem 4&lt;/h2&gt;
&lt;p&gt;problem 4中，我们考察了对于semi-supervised Learning的表达式，实际应用时，我们可能有的数据会有标签，有的没有，因此我们结合EM中假设  $w_{ij}=P(z=j|x^i,\theta)$  以及标签数据，在经过大量的计算之后，得到&lt;/p&gt;
&lt;p&gt;$\begin{aligned} \phi_j &amp;#x26;= \frac{\sum_{i=1}^m w_j^{(i)} + \alpha \sum_{i=1}^{\tilde{m}} 1{\tilde{z}^{(i)} = j}}{m + \alpha \tilde{m}} \ \mu_j &amp;#x26;= \frac{\sum_{i=1}^m w_j^{(i)} x^{(i)} + \alpha \sum_{i=1}^{\tilde{m}} 1{\tilde{z}^{(i)} = j} \bar{x}^{(i)}}{\sum_{i=1}^m w_j^{(i)} + \alpha \sum_{i=1}^{\tilde{m}} 1{\tilde{z}^{(i)} = j}} \ \Sigma_j &amp;#x26;= \frac{\sum_{i=1}^m w_j^{(i)} (x^{(i)} - \mu_j)(x^{(i)} - \mu_j)^T + \alpha \sum_{i=1}^{\tilde{m}} 1{\tilde{z}^{(i)} = j} (\bar{x}^{(i)} - \mu_j)(\bar{x}^{(i)} - \mu_j)^T}{\sum_{i=1}^m w_j^{(i)} + \alpha \sum_{i=1}^{\tilde{m}} 1{\tilde{z}^{(i)} = j}} \end{aligned}$&lt;/p&gt;
&lt;p&gt;最后我们进行了coding任务，结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;发现如果加上了一定的标签数据，那么看上去准确度会大大的提高&lt;/p&gt;
&lt;p&gt;具体实现代码见&lt;/p&gt;
&lt;h2&gt;Problem 5&lt;/h2&gt;
&lt;p&gt;在本题中我们主要使用k-means，将一张256色的图片，在保证图片大致效果不变下，变成一张16色的图片。而使用k-means去自主寻找相应的颜色压缩图片感觉还是非常的有意思的。而且实际效果非常好。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;左侧为原始图，右侧为压缩图&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229：Ps4解读——强化学习探讨与实现</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps4-rl/cs229-ps4-rl</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-ps4-rl/cs229-ps4-rl</guid><description>CS229：Ps4解读——强化学习探讨与实现</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;终于终于到了最后一个problem set 啦！！！这一块主要是对于无监督学习的收尾以及强化学习的探讨，虽然我们调程序的时候，见到各种各样的维数不匹配仍然非常的头疼，但是以及有了非常大的改进，这一个problem set的实现结果最后也是非常的漂亮。&lt;/p&gt;
&lt;p&gt;具体作业内容以及答案见下&lt;/p&gt;
&lt;h2&gt;Problem 1&lt;/h2&gt;
&lt;p&gt;这道题目主要是用numpy实现了卷积神经网络，具体代码见下&lt;/p&gt;
&lt;p&gt;主要难度在于反向传播的实现，对于pool层梯度的传播路径以及conv层的传播都是非常烦的，具体内容之后在cs230的文章中会详细说明&lt;/p&gt;
&lt;p&gt;最后使用一个单层卷积层以及一个全连接层的网络，训练结果如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Problem 2&lt;/h2&gt;
&lt;p&gt;强化学习中，在最基本的MDP模型中，两个参数  $\pi(a,s),R(a,s)$  是需要我们训练以及模拟得到的，而实际情况中，训练情况与实际情况关系会较为复杂，导致  $\pi_0(a,s）$  与  $\hat{\pi_0}(a,s）$  差距可能较大，但于此同时R又会相对简单，为了评价  $\pi_1(a,s)$  可能的效果，我们探究了使用过往的  $\pi_0(a,s),R(a,s)$  去评判由(a,s)生成新的  $\pi_1(a,s),R(a,s)$  如何减小误差&lt;/p&gt;
&lt;p&gt;（a)(b)(c)中论证了当基于经验模型  $\pi_0(a,s)$  去判断下一个动作时，只需要加上  $\frac{\pi_1}{\hat{\pi_0}}$  的修正，实际的效果和根据  $\pi_1(a,s),R(a,s)$  做出的决策的均值相同，数学上为&lt;/p&gt;
&lt;p&gt;$\mathbb{E}&lt;em&gt;{\substack{s \sim p(s) \ a \sim \pi_0(s,a)}} \frac{\pi_1(s,a)}{\pi_0(s,a)} R(s,a)=\mathbb{E}&lt;/em&gt;{\substack{s \sim p(s) \ a \sim \pi_1(s,a)}} R(s,a)$  ，从而将基于新模型进行判断转换为基于旧模型进行判断（&lt;/p&gt;
&lt;p&gt;|  |
| --- |
| 重要性采样 |&lt;/p&gt;
&lt;p&gt;）&lt;/p&gt;
&lt;p&gt;(d)则是考虑了对于经验上R(s,a)与实际上R(s,a)有差别的情况，此时我们考虑对于策略  $\pi(s,a)$  进行泰勒展开，有&lt;/p&gt;
&lt;p&gt;$\mathbb{E}&lt;em&gt;{\substack{s \sim p(s) \ a \sim \pi_0(s,a)}} \left( \left(\mathbb{E}&lt;/em&gt;{a&apos; \sim \pi_1(s,a&apos;)} \hat{R}(s,a&apos;)\right) + \frac{\pi_1(s,a)}{\hat{\pi}&lt;em&gt;0(s,a)} (R(s,a) - \hat{R}(s,a)) \right)=\mathbb{E}&lt;/em&gt;{\substack{s \sim p(s) \ a \sim \pi_1(s,a)}} R(s,a)$  只要  $R(s,a)=\hat{R(s,a)},\pi_0(s,a)=\hat{\pi_0}(s,a)$  中有一个成立就行。（&lt;strong&gt;双重稳健估计&lt;/strong&gt; ）&lt;/p&gt;
&lt;p&gt;从而我们发现，如果  $\pi_0$  相对简单，或者是奖励机制简单，使用经验模型去预测就不会有系统误差。&lt;/p&gt;
&lt;h2&gt;Problem 3&lt;/h2&gt;
&lt;p&gt;主要是对于PCA能反映出数据中的特征向量（数据空间中的若干个相互垂直的轴）的理论分析，比较的容易&lt;/p&gt;
&lt;h2&gt;Problem 4&lt;/h2&gt;
&lt;p&gt;ICA中我们通过假设数据本身的分布，实现了对于若干个掺杂数据的分离，而我们当时只是说不能使用Gaussian作为原始分布，这里我们首先证明了这个是不可以的，最后通过假设数据分布为Laplace分布实现了5个数据的分离，实际操作效果下来非常不错。&lt;/p&gt;
&lt;h2&gt;Problem 5&lt;/h2&gt;
&lt;p&gt;这道题目使用强化学习去实现了控制小车，使得小车上方的杆子不要倒下来的一个算法。&lt;/p&gt;
&lt;p&gt;在本题中，我们的更新策略是将过往所做过决策以及产生的结果作为“随机实验”的结果，并用来更新  $\pi,R$&lt;/p&gt;
&lt;p&gt;而对于每一步的策略的选取，我们通过使用Bellman方程去计算价值  $V(a,s)$  ，并由此更新策略。&lt;/p&gt;
&lt;p&gt;最后的结果如图，大概到了60个iteration就收敛了，也就是当杆子摔倒了60次之后终于可以做出比较正确的决策了。（还是有一点点慢的。）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS224W 食用指南</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs224w-usage-guide/cs224w-usage-guide</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs224w-usage-guide/cs224w-usage-guide</guid><description>CS224W课程学习指南，包括学习方法和资源推荐。</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在对LLM略有了解之后，我在想ai的未来会是什么，对于知识的建立，LLM无论是数据，还是参数，都是以&lt;strong&gt;网格状/线性&lt;/strong&gt; 的方式去建立，这和人脑的&lt;strong&gt;千奇百怪的连接方式&lt;/strong&gt; 有非常大的距离。而使用&lt;strong&gt;G=(V,E)&lt;/strong&gt; 的图论是更加贴近人的语言，带着这个观点，我开始学习著名的&lt;strong&gt;CS224W&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;关于这门课程，我使用的资料是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;21winter视频课&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;25fall的slides以及作业，总共包括3份homework以及6个实验&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主讲老师Jure Leskovec是GraphSAGE:推动GNN走向大规模学习的奠基人，除了口音有点重以外，上课&lt;strong&gt;有非常多的工业案例&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;我的食用方法大致为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;21win包含**“图 ML → 图表示学习 → GNN → 理论 → 规模化** ”的整个过程，为了体系的完整性，选择这个的视频课进行观看&lt;/li&gt;
&lt;li&gt;对于前沿GNN科技，25fall包括transformer in Graph，规模化等技术，&lt;strong&gt;可以使用25Fall进行补充&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;作业&amp;#x26;&amp;#x26;实验使用25fall的版本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这门课的基本结构&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;21win lecture1-5:&lt;strong&gt;ML in Graph&lt;/strong&gt; 介绍图性质刻画以及图上的ML算法&lt;/li&gt;
&lt;li&gt;21win lecture6-8:介绍GNN以及经典模型&lt;/li&gt;
&lt;li&gt;21win lecture8-9:GNN的应用案例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;21win lecture10-12&lt;/strong&gt; :GNN理论局限性，一些常见问题&lt;/li&gt;
&lt;li&gt;对于GNN前沿，如知识图谱，推荐系统等，看25fall lecture8-11的slides&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这个老师听说是stanford最帅的professor&lt;/p&gt;
&lt;p&gt;这门课的实验以及作业不是特别多(点名批评cs336),希望可以在12月结束之前干完。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BdQE_IJL.jpg"/><enclosure url="/_astro/background.BdQE_IJL.jpg"/></item><item><title>CS229  强化学习：MDP以及其优化方法</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-rl-mdp-opt/cs229-rl-mdp-opt</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-rl-mdp-opt/cs229-rl-mdp-opt</guid><description>CS229  强化学习：MDP以及其优化方法</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS229最后介绍了强化学习的内容，与之前的规定了优化的方向以及最后的目标不同，强化学习是通过&lt;strong&gt;对机器的行为设定奖励并通过实验自行学习到最优的解决方案&lt;/strong&gt; 的一种学习手段，接下来我们将会介绍最为基本的Markov Decision Process以及其常见的改进手段。&lt;/p&gt;
&lt;h2&gt;Basic MDP&lt;/h2&gt;
&lt;h3&gt;基本要素&lt;/h3&gt;
&lt;p&gt;想要让机器知道对于那一步应该采取什么样的措施，我们需要对于机器在那一步做出什么样的行为设定合理的&lt;strong&gt;奖励&lt;/strong&gt; $R$ ，我们需要预先知道机器** 可能的状态** $S$ 并且规定好机器会做出的反应 $A$ ，最后在机器进行决策的时候我们会有** 过往的经验&lt;strong&gt;矩阵 $P_{sa}(s&apos;)$ 表示s状态下使用a操作会到达s’的概率, 最后对于&lt;/strong&gt; 奖励计算**我们还会设置一个折扣值 $\gamma$ 来衡量时间的因素。&lt;/p&gt;
&lt;p&gt;以上便是MDP的基本要素， ${S,A,P_{sa},\gamma,R}$ 变为我们所有的参数。对于训练寻找最优的策略 $\pi$ 的过程中，总体的步骤为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初始化：最开始的状态为 $S_0$ 有 $S_0\sim P_{s_0a_0}$&lt;/li&gt;
&lt;li&gt;步进：我们由此在 $P_{s_0a_0}$ （过往的经验）中&lt;strong&gt;以某种规则&lt;/strong&gt; 选择步骤 $a_0$ 得到 $s_1$ ,并以此类推，得到 $s_0 \xrightarrow{a_0} s_1 \xrightarrow{a_1} s_2 \xrightarrow{a_2} s_3 \xrightarrow{a_3} \cdots s_n$&lt;/li&gt;
&lt;li&gt;调整策略：到了 $s_n$ 之后基于之前的行为对于 $P_{sa}$ 进行调整，然后继续步进。&lt;/li&gt;
&lt;li&gt;直到最后 $P_{sa}$ 收敛，我们得到了一个合理的策略选择方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;评价函数&lt;/h3&gt;
&lt;p&gt;在步进中，我们已经有了可能进行选择的策略以及基于过往的经验的概率 $P_{sa}$ ，而此时对于场景 $s_0$ 而言，需要对不同的操作进行评估，并形成对于一个策略 $\pi(s_0)$ 。&lt;/p&gt;
&lt;p&gt;对于 $(s_0,a_0)$ 而言，如果之后我们的操作是 $(s_1,a_1),(s_2,a_2)...$ 的话，对于整体的奖励函数进行累加，得到&lt;/p&gt;
&lt;p&gt;$L(S,A)=R(s_0,a_0)+R(s_1,a_1)+R(s_2,a_2)+....$&lt;/p&gt;
&lt;p&gt;考虑到时间的因素，我们对于 $s_1,s_2$ 都是假设之后的状态以及做出的动作，应该加上一个因子来衡量时间的影响&lt;/p&gt;
&lt;p&gt;$L(S,A)=R(s_0,a_0)+\gamma R(s_1,a_1)+\gamma^2 R(s_2,a_2)+....$&lt;/p&gt;
&lt;p&gt;常常我们的损失只会与我们的状态有关，比如一个机器人如果倒地了那么就将损失定为-1，否则为0。而对于 $a_0$&lt;/p&gt;
&lt;p&gt;对于整体的影响为了简化问题不考虑。于是有&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对于 $s_0$ 以及预测之后动作列 $s_1,s_2,s_3,...$ 的损失函数为&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$L(S)=R(s_0)+\gamma R(s_1)+\gamma^2 R(s_2)+\gamma^3 R(s_3)...$&lt;/p&gt;
&lt;h3&gt;从评价函数到策略选取&lt;/h3&gt;
&lt;p&gt;对于 $s_0$ 处的损失取平均值，有 $L(S)=E(R(s_0)+\gamma R(s_1)+\gamma^2 R(s_2)+\gamma^3 R(s_3)...)$ 我们希望得到一个最合适的策略 $a=\pi(s)$  对于之后的步骤选取我们都使用这个策略，于是有定义&lt;/p&gt;
&lt;p&gt;$V^\pi(s) = \mathbb{E} \left[ R(s_0) + \gamma R(s_1) + \gamma^2 R(s_2) + \cdots ,\middle|, s_0 = s, \pi \right]$&lt;/p&gt;
&lt;p&gt;该式子等价于 $V^\pi(s) = R(s) + \gamma \sum_{s&apos; \in S} P_{s\pi(s)}(s&apos;) V^\pi(s&apos;)$&lt;/p&gt;
&lt;p&gt;我们的策略是希望这个策略让损失最小，如果有 $V^&lt;em&gt;(s) = \max_{\pi} V^\pi(s)$ 的话,那么有 $V^&lt;/em&gt;(s) = R(s) + \max_{a \in A} \gamma \sum_{s&apos; \in S} P_{sa}(s&apos;) V^*(s&apos;)$ 该方程也称为&lt;strong&gt;Bellman equation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有了对于每一个步骤的评价函数，那么对于** 策略的选取**为&lt;/p&gt;
&lt;p&gt;$a^&lt;em&gt;=\pi^&lt;/em&gt;(s) =\arg\max_{a\in A} V(s)= \arg\max_{a \in A} \sum_{s&apos; \in S} P_{sa}(s&apos;) V^*(s&apos;)$&lt;/p&gt;
&lt;p&gt;以上是数学上的一个推导，而我们对于具体的计算的话，我们发现 $V^*(s)$&lt;/p&gt;
&lt;p&gt;解的话为一个&lt;strong&gt;线性方程组&lt;/strong&gt; ，如果直接求解会比较的慢，实际的使用中，一种常见的方法为&lt;strong&gt;value iteration&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step 1&lt;/strong&gt; :首先将 $V(s)$ 全部初始化为0&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step 2&lt;/strong&gt; ：重复步骤知道收敛,每一步中根据Bellman Equation对于 $V(s)$ 进行更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于之后的动作的选取为 $\pi(s) := \arg\max_{a \in A} \sum_{s&apos; \in S} P_{sa}(s&apos;) V(s&apos;)$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总结而言&lt;/strong&gt; ，对于步进中我们会基于&lt;strong&gt;过往的经验&lt;/strong&gt; $P_{sa}$ 选取在当下看来最优秀的策略，并且形成一套自己的策略进而选取在 $s_i$ 下的操作 $a_i$ .&lt;/p&gt;
&lt;h3&gt;更新经验 $P_{sa}(s&apos;)$&lt;/h3&gt;
&lt;p&gt;在步进了一段时间之后，我们需要对于过往的经验进行更新，将最近若干次的实验的结果给放进去，实际情况下，我们会让机器人使用当前的策略进行运动，记录下实际的数据，也就是** 将实验中的N(s,a,s’)作为数据来源，对于**&lt;/p&gt;
&lt;p&gt;** $P_{sa}(s&apos;)$ 进行更新**&lt;/p&gt;
&lt;p&gt;数学表达为 $ \boxed{P_{sa}(s&apos;) \leftarrow \frac{N(s, a, s&apos;)}{\sum_{s&apos;&apos;} N(s, a, s&apos;&apos;)}} $&lt;/p&gt;
&lt;p&gt;最后合起来，即有MDP(使用贪心策略进行动作选取(Bellman Equation)）的基本步骤&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先随机初始化 $\pi,V,P_{sa}(s&apos;)$ 并且设定好R&lt;/li&gt;
&lt;li&gt;重复一下步骤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（1）使用 $\pi$ 进行若干轮实验&lt;/p&gt;
&lt;p&gt;（2）更新 $P_{sa}(s&apos;)$&lt;/p&gt;
&lt;p&gt;（3）使用value iteration对于 $V(s)$ 进行更新，进而更新我们的 $\pi$&lt;/p&gt;
&lt;p&gt;以上是&lt;strong&gt;最为基本的MDP&lt;/strong&gt;,他纯纯使用** 贪心&lt;strong&gt;算法，而且我们的操作是只有&lt;/strong&gt; 离散**的情形。而在此基础上还可以进行一定的改进&lt;/p&gt;
&lt;h2&gt;Improved MDP&lt;/h2&gt;
&lt;h3&gt;MDP+Randomness&lt;/h3&gt;
&lt;p&gt;考虑如下的一个场景：如果我们每一步会扣除点数-0.05&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果我们使用MDP的话，会直接通往+1的点，但是实际的话** 贪心并不是最优的策略**,于是我们对于动作的选取方案改变为： $a=\eta \pi(s)+ (1-\eta)a_{randomly choosen}$&lt;/p&gt;
&lt;p&gt;这样的话添加了一些** 随机性**，就可以有比较优良的结果了。&lt;/p&gt;
&lt;h3&gt;连续动作空间的MDP&lt;/h3&gt;
&lt;p&gt;如果我们的状态空间为连续的，比如对于一个机器人的的位置与角度。而此时我们有若干解决方案&lt;/p&gt;
&lt;p&gt;** Method 1:**&lt;/p&gt;
&lt;p&gt;将我们的state的变量  $(x^1,x^2,…x^m)$  所在的空间分割成若干个网格(离散化)，然后使用之前的方法。&lt;/p&gt;
&lt;p&gt;这样的好处是能训练完成之后机器人会有非常优秀的表现，坏处是离散化之后的state会非常的大，对于变量过多时不建议考虑&lt;/p&gt;
&lt;p&gt;** Method 2:**&lt;/p&gt;
&lt;p&gt;使用外部的物理引擎，这一块请咨询** userlzh** from ustcsgy&lt;/p&gt;
&lt;p&gt;** Method 3:Fitted Value iteration**&lt;/p&gt;
&lt;p&gt;我们之前对于策略的选取是通过value iteration将 $P_{sa}(s)\Rightarrow V(s)\Rightarrow \pi(s)$ ,而对于Bellman equation中我们无法取遍所有的a,于是对于 $V(s)$ 就需要通过神经网络(如规定一系列的基函数 $\phi(s),V(s)=\theta^T\phi(s)$ )去进行逼近,我们想要该案例去学习这些参数具体步骤为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step1:&lt;/strong&gt; 随机选取m个状态 $s^1,s^2,.....s^m$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step2:&lt;/strong&gt; 重复一下步骤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（1）对于每一个i，计算在每一个动作a下面的损失 $q(a) = \frac{1}{k} \sum_{j=1}^{k} R(s^{(i)}) + \gamma V(s&apos;_j)$ (将q作为对于 $V(s^i)$&lt;/p&gt;
&lt;p&gt;的一个样本)&lt;/p&gt;
&lt;p&gt;（2） $y^i=max_a q(a)$ （得到 $V^*(s^i)$ 的样本）&lt;/p&gt;
&lt;p&gt;（3）使用 $(s^i,y^i)$ 去更新参数 $\theta := \arg\min_{\theta} \frac{1}{2} \sum_{i=1}^{m} \left( \theta^T \phi(s^{(i)}) - y^{(i)} \right)^2$&lt;/p&gt;
&lt;p&gt;然后我们进行正常的MDP即可。&lt;/p&gt;
&lt;p&gt;以上变为强化学习的&lt;strong&gt;最为基本&lt;/strong&gt; 的内容，对于具体的代码实现(我们已经给出了伪代码)请参见github仓库，MDP(使用贪心进行策略选取，并以此优化策略)的方法还是&lt;strong&gt;非常的精妙的&lt;/strong&gt; ，更多的强化学习的内容之后我们会在cs236中进行学习。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:监督学习(一）—— 线性回归，梯度下降与逻辑回归的原理</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-1-linreg-logreg/cs229-supl-1-linreg-logreg</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-1-linreg-logreg/cs229-supl-1-linreg-logreg</guid><description>CS229:监督学习(一）—— 线性回归，梯度下降与逻辑回归的原理</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;听了后面的Lecture 5, 正好从更高的视角来观察之前学过的这些模型与算法。&lt;/p&gt;
&lt;p&gt;对于机器学习的主要步骤为(1)希望对于待预测的输入x进行预测 （2）将x扔进一个假设（hypothesis)  $h_{\theta}(x)$  中（3）函数会给出我们需要的预测  $\hat{y}$  ，而对于假设  $h_{\theta}(x) $  的求解是通过给一个Training sets, 通过某种学习算法，得出假设中所需要的参数值。&lt;/p&gt;
&lt;p&gt;接下来我们将会基于以下假设来推导出线性回归的假设函数  $h_{\theta}(x)$  以及所需要的损失函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;假设响应y和输入x为线性关系，即为存在一组参数  $\theta \in R^{n+1}$  使得  $y=\theta^T x $  ，我们认为  $x_0=1$  ,代表常数项&lt;/li&gt;
&lt;li&gt;对于实际的情况，由&lt;strong&gt;中心极限定理&lt;/strong&gt; 我们知y和  $h_{\theta}(x)$  之间的差值  $\Delta    $  可以认为满足正态分布&lt;/li&gt;
&lt;li&gt;对于训练过程中  $\theta$  目标是使得  $\Delta$  的最大似然估计最大&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于以上的假设，我们有&lt;/p&gt;
&lt;p&gt;$L(\theta) =\Pi^m_{i=1}P(\Delta)\ =\Pi^m_{i=1} P(y^i|x^i,\theta)\ =\Pi^m_{i=1} \frac{1}{\sqrt{2\pi}\sigma}exp(-\frac{(y^i-\theta^T x^i)^2}{2\sigma^2}) $ 目标是使得这个函数最大，即为让该函数的对数函数最大，左右取对数&lt;/p&gt;
&lt;p&gt;$MLE=l(\theta)=log(L\theta) \ =\Pi^m_{i=1} \frac{1}{\sqrt{2\pi}\sigma}exp(-\frac{(y^i-\theta^T x^i)^2}{2\sigma^2}) =-mlog(\sqrt{2\pi}\sigma) -\frac{1}{2\sigma^2}\Sigma^m_{i=1}(y^i-\theta^T x_i)^2 $  从而解释了为什么我们对于线性回归函数在别的教科书上会取  $J(\theta)=\frac{1}{2}\Sigma^m_{i=1} (y^i-\theta^T x^i)^2$  为损失函数，对于指数取2是因为正态分布可以推导出来这个东西，而目标是损失函数最小，这个自然符合“最大似然估计最大”。&lt;/p&gt;
&lt;p&gt;以上都是对于线性回归，而对于逻辑回归，我们做的假设是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$h_{\theta}(x)=P(y|x,\theta),y=argmax_y(P(y|x)),y\in{0,1}$&lt;/li&gt;
&lt;li&gt;$h_{\theta}(x)=sigmoid(x)=\frac{1}{1+e^{-\theta^T x}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样是使用最大似然估计，这里我们有  $P(y^i|x^i,\theta)=h_{\theta}(x)^{y^i}(1-h_\theta(x))^{1-y^i}$  可以得到&lt;/p&gt;
&lt;p&gt;$MLE=l(\theta)=\Sigma^m_{i=1} y^ilog(h_\theta(x))+(1-y^i) log(1-h_{\theta}(x))$&lt;/p&gt;
&lt;p&gt;这个即为我们想要的损失函数&lt;/p&gt;
&lt;p&gt;有了损失函数（through learning algorithm),我们如何通过损失函数求解出相对应的参数  $\theta$  ，最为常用的就是&lt;strong&gt;梯度下降&lt;/strong&gt;,一般的模型而言，公式为&lt;/p&gt;
&lt;p&gt;$\theta:=\theta-\alpha \frac{\partial}{\partial \theta} J(\theta)$&lt;/p&gt;
&lt;p&gt;其中  $\alpha$  我们一般称为是学习率，对于线性回归（Exponential family 中的正态分布），逻辑回归（Exponential family 中的伯努利分布），我们有Exponential family中的统一公式&lt;/p&gt;
&lt;p&gt;$\theta_j:=\theta_j +\alpha(y^i-h_{\theta}(x^i)) x^i$&lt;/p&gt;
&lt;p&gt;在使用的时候，我们一般是用&lt;/p&gt;
&lt;p&gt;$\theta_j:=\theta_j +\alpha\frac{1}{m}\Sigma^m_{i=1}(y^i-h_{\theta}(x^i)) x^i$&lt;/p&gt;
&lt;p&gt;以上是最为重要的东西，下面是一些辅助的特殊的算法（设计非常精妙，但是相当于数学中的奇技淫巧，不能说是开创性的，大纲性的内容。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;随机梯度下降（stochastic gradient descent)：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;实际使用的过程中，由于正常的梯度下降的过程在每一个iteration中都需要将整个数据集给遍历一遍，现实中的数据集非常大，每次操作需要遍历一遍过于浪费时间了，因此我们考虑使用&lt;/p&gt;
&lt;p&gt;$\theta_j:=\theta_j +\alpha(y^i-h_{\theta}(x^i)) x^i$&lt;/p&gt;
&lt;p&gt;i不断从1-m中来回遍历，而且对于学习率也随着时间不断下降，这样操作的坏处是可能结果不会收敛，精度会比较小，但是好处是节约内存。&lt;/p&gt;
&lt;p&gt;2.Newton方法&lt;/p&gt;
&lt;p&gt;Newton方法是一种快速逼近零点的方法（** 特别注意，最好取要逼近的函数上只有一个0点**）&lt;/p&gt;
&lt;p&gt;Newton方法的操作见示意图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;蓝色的曲线是  $f(x)$  ,我们想要找到f(x)=0的解，对于最一开始随便找的点  $x_0 $  可以使用牛顿法找到  $x_1$  ,依次找下去，最后会收敛到零点。用数学去表示即为  $\theta:=\theta-\frac{f(\theta)}{f&apos;(\theta)}$&lt;/p&gt;
&lt;p&gt;由于我们在求解机器学习中的参数  $\theta$  的时候，是使用  $J&apos;(\theta)=0$  去求解的，因此有&lt;/p&gt;
&lt;p&gt;$\theta:=\theta-\frac{J&apos;(\theta)}{J&apos;&apos;(\theta)}$  ，一般的形式为  $\theta:=\theta-H^{-1}\nabla_{\theta} J(\theta)$  ,其中  $H=\frac{\partial^2 J(\theta)}{\partial \theta_i\partial \theta_j}$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用Newton方法的优点是它非常的快，因为它是二次收敛的（收敛的速度是梯度下降的平方倍），因此对于参数大小比较小的时候(10-100）的时候还是比较好的。&lt;/li&gt;
&lt;li&gt;虽然但是由于这里面涉及到了求解矩阵的逆的过程，同时由于求逆，还要保证Hessian矩阵的行列式不可以为0，因此还是要慎重使用（参考Problem 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3.LWR(Locally Weighted Regression)&lt;/p&gt;
&lt;p&gt;对于之前的求解过程中，我们在训练的时候对于每一个训练数据的权重都是相同的，实际上我们希望偏重于我们目标位置处的点，因此我们使用Locally Weighted Regression,即为添加一些权重项，很自然的我们想要使用正态分布来考虑。&lt;/p&gt;
&lt;p&gt;即为  $J(\theta)=\Sigma^m_{i=1} w^i (y^i-\theta^T x^i)^2$  ,其中  $w^i=exp(-\frac{(x^i-x)^2}{2\tau^2})$&lt;/p&gt;
&lt;p&gt;在训练的过程中，对于给定的xi,我们计算这个点的J，结合该点的权重，拟合出来响应点x的参数，最后得到输出。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229：监督学习(二）—— GLM视角下的模型</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-2-glm-models/cs229-supl-2-glm-models</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-2-glm-models/cs229-supl-2-glm-models</guid><description>CS229：监督学习(二）—— GLM视角下的模型</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;花了两天的时间把常见的linear regression, binary regression, k-classes regression几个常见的模型学习了一下，Andrew Ng将每一个模型的来龙去脉，包括hypothesis, loss function原因以及不同模型之间的关系进行了详细的说明，并且全部归入了GLM模型中，从而推导了k-classes classification（softmax) 的细节，真的让我大彻大悟。&lt;/p&gt;
&lt;p&gt;GLM的核心是通过通过满足Exponential family(指数族函数)的概率分布（pdf) ,并通过这些分布的natural parameters(如  $\sigma, \mu,\lambda$  之类的东西）和  $\eta=\theta^T x$  之间的函数  $\phi=g(\eta)$  建立联系，从而通过  $h_{\theta}(x)=E(y|x,\theta)=\frac{\partial}{\partial \eta_j} a(\eta)$  得出了我们结果在R上的概率分布。（个人认为这个是LR,BR的最核心的地方）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取概率分布为Bernoulli分布，则  $P(y|x,\theta)=\phi^{y_i}(1-\phi)^{1-y_i}$ ， 且  $\phi=\frac{1}{1+e^{-\eta}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;取概率分布为Gaussian分布，则  $P(y|x,\theta)=\frac{1}{\sqrt{2\pi}} exp(-(\frac{(y_i-\mu)^2}{2}))$  ,且  $\phi=\eta$&lt;/p&gt;
&lt;p&gt;由于特殊的Exponential family为  $P(y,\eta)=b(y)exp(\eta^T T(y)-a(\eta))$  ，我们可以得到linear regression,以及binary regression 的相应函数。&lt;/p&gt;
&lt;p&gt;而对于损失函数而言，对于GLM中的模型，我们都有&lt;/p&gt;
&lt;p&gt;$\theta_j:=\theta_j+\alpha (y^i-h_\theta(x^i))x^i_j$&lt;/p&gt;
&lt;p&gt;带入即有linear regression 以及binary regression的损失函数。&lt;/p&gt;
&lt;p&gt;使用这个方法我们可以得到softmax的响应函数以及损失函数。&lt;/p&gt;
&lt;p&gt;对于Exponential family中的函数的性质，由于我Problem set 1 中的东西还没有做，之后再写一篇文章。&lt;/p&gt;
&lt;p&gt;以上个人感觉是最为主要的内容，Andrew Ng还讲了一些别的东西，如为什么使用least square, Newton methods, Linear weight regression,以及一些数学上的性质。之后我统一写一篇文章来细说这些东西。&lt;/p&gt;
&lt;p&gt;最后附上我的课堂笔记，刚开始尝试使用英文记笔记，可能会有非常多的语法错误，文章中的示意图是我手画的，可能会比较丑陋，大家不要介意。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;以及Lecture 4的笔记&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/background.CQiwm9he.jpg"/><enclosure url="/_astro/background.CQiwm9he.jpg"/></item><item><title>CS229:监督学习（三）—— 简单粗暴的生成式学习算法(1):GDA</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-3-1-gda/cs229-supl-3-1-gda</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-3-1-gda/cs229-supl-3-1-gda</guid><description>CS229:监督学习（三）—— 简单粗暴的生成式学习算法(1):GDA</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;拖了2天了，原本想要看完Lecture 6就写这篇文章的，但是Andrew Ng.讲的实在是太好了，搞得我非常想要把SVM给全部学完，结果是看到了Lecture 8, 才发现对于&lt;strong&gt;Generative Learning Algorithm&lt;/strong&gt; (生成式学习算法)还没有整理，今天来给大家介绍以下对于一个dataset可以直接使用的&lt;strong&gt;quick and rough&lt;/strong&gt; 的算法：GDA和Naive Bayes Method&lt;/p&gt;
&lt;p&gt;首先我们来介绍一类全新的模型。&lt;/p&gt;
&lt;h2&gt;生成式学习算法&lt;/h2&gt;
&lt;h3&gt;Generative Learning Algorithm:&lt;/h3&gt;
&lt;p&gt;对于我们之前学习的，无论是逻辑回归（Logistic Regression），还是线性回归(Linear Regression)，我们对于求解参数  $\theta $  的方式都是使用对于在满足当前数据集和参数  $\theta,x$  下的最大似然估计  $MLE$  。  $MLE=log(L(\theta))=\Sigma_{i=1}^m log(p(y^i|x^i,\theta))$  （conditional likelihood)。&lt;strong&gt;直觉上看&lt;/strong&gt; 就是通过feature去求解在那个class中。这个是之前的中心思想&lt;/p&gt;
&lt;p&gt;而由于可以通过feature去求解在那个class中，我们相应的，也可以考虑对于每一个class,可能会在有那些feature,即为考虑  $p(x|y)$  这个就是Generative Learning Algorithm，相应的，在GLA中使用的MLE中的函数&lt;/p&gt;
&lt;p&gt;$L(parameters)=\Pi^m_{i=1} P(x^i,y^i;params)=\Pi ^m_{i=1} P(x^i|y^i,params)P(y^i|params)$  (Joint Likelihood)&lt;/p&gt;
&lt;p&gt;理解上可以认为是对于conditional likelihood中的  $P(x^i|\theta)=P(x^i)=1$  (虽然不严格）&lt;/p&gt;
&lt;p&gt;对于GLA而言，如果我们已知  $p(x|y)$  ，在预测的时候仍然是在给定的  $x,\theta $  下对于y进行预测，那么这个时候对于两者之间联系的桥梁就是Bayes公式：&lt;/p&gt;
&lt;p&gt;$P(y|x)=\frac{P(x|y)P(y)}{P(x)}=\frac{P(x|y)P(y)}{\Sigma P(x|y^i)P(y^i)}$&lt;/p&gt;
&lt;p&gt;特别的，如果我们是进行一个二分类问题，  $y\in{0，1}$  预测的时候即为&lt;/p&gt;
&lt;p&gt;$argmax_y(P(y|x))=argmax_y(P(x|y)P(y))$&lt;/p&gt;
&lt;h2&gt;GDA(高斯判别分析)&lt;/h2&gt;
&lt;h3&gt;理论基础&lt;/h3&gt;
&lt;p&gt;有了之前的分析，我们想要使用这个方法来进行&lt;strong&gt;二分类问题&lt;/strong&gt; ，过去我们是使用Logistic Regression去完成的，如今只需要对于  $P(x|y)$  和P(y)进行求解即可。为此，我们可以做出一些小小的数学假设(已知  $y \in {0,1}$  )：&lt;/p&gt;
&lt;p&gt;$P(y=1)=\phi_y\ P(x|y=0)=\frac{1}{(2\pi)^\frac{n}{2}|\Sigma|^\frac{1}{2}}exp(-\frac{1}{2} (x-\mu_0)^T \Sigma^{-1}(x-\mu_0))\ P(x|y=1)=\frac{1}{(2\pi)^\frac{n}{2}|\Sigma|^\frac{1}{2}}exp(-\frac{1}{2} (x-\mu_1)^T \Sigma^{-1}(x-\mu_1))$&lt;/p&gt;
&lt;p&gt;以上的假设对于非常多的情况是成立的，因为对于满足y的特征&lt;strong&gt;在很多情况下&lt;/strong&gt; 可以看成是满足一个正态分布（只是这里的正态分布是多元的正态分布）&lt;/p&gt;
&lt;p&gt;而对于多元的正态分布，它的两个参数  $\mu_1\in R^n,\Sigma \in R^{n\times n}$  分别表示其均值和协方差，以2维为例子，考虑以  $x_1,x_2,p(x_1,x_2)$  为坐标系建系，其几何图形长成&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;二维正态分布示意图&lt;/p&gt;
&lt;p&gt;考虑它在水平面上的等高线（contour)的投影，长成&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;其参数的几何意义可以看成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$\mu$  可以看成是将这个圆环族在水平面上进行平移&lt;/li&gt;
&lt;li&gt;$\Sigma$  对角线上的元素可以看成是将该圆环进行等比例的放大和缩小，而对于非对角线上的元素就是对于对于圆环变成椭圆&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;推导过程&lt;/h3&gt;
&lt;p&gt;使用以上的假设，参数为  $\phi,\mu_0,\mu_1,\Sigma$  ,我们可以由以上的假设求得&lt;/p&gt;
&lt;p&gt;$P(x^i|y^i,params)=\frac{1}{(2\pi)^\frac{n}{2}|\Sigma|^\frac{1}{2}}exp(-\frac{1}{2} (x^i-\mu_{y^i})^T \Sigma^{-1}(x^i-\mu_{y^i}))$&lt;/p&gt;
&lt;p&gt;对于参数的求解，使用GLA中的损失函数，  $L(\phi,\mu_0,\mu_1,\Sigma)=\Pi ^m_{i=1} P(x^i|y^i,\phi,\mu_0,\mu_1,\Sigma)P(y^i|\phi,\mu_0,\mu_1,\Sigma)$&lt;/p&gt;
&lt;p&gt;带入以上的假设，对于参数进行求导，我们得到&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GDA的参数估计&lt;/strong&gt; $\phi=\frac{\Sigma^m_{i=1} y^i}{m}=\frac{\Sigma^m_{i=1} 1{y^i=1}}{m} \  \mu_0=\frac{\Sigma^m_{i=1} 1{y^i=0} x^i}{\Sigma^m_{i=1} 1{y^i=0}} \  \mu_1=\frac{\Sigma^m_{i=1} 1{y^i=1} x^i}{\Sigma^m_{i=1} 1{y^i=1}} \  \Sigma=\frac{1}{m}\Sigma^m_{i=1} (x^i-\mu_{y^i})(x^i-\mu_{y^i})^T\$  具体的过程之后在Problem Set 1 的T1中有，过一段时间我会写一篇关于PS1的文章(PS1已经完成了，只差写文章了）。&lt;/p&gt;
&lt;h3&gt;讨论&lt;/h3&gt;
&lt;p&gt;对于GDA的参数理解，对于  $\phi,\Sigma$  我们可以分别理解为整体中的所有的y的值的一个最大似然估计，以及对于所有给出的值的一个方差。&lt;/p&gt;
&lt;p&gt;对于  $\mu_0$  而言即为在y=0这一类中的** 所有x的特征的提取**。对于另外一个也是同样的理解方式。&lt;/p&gt;
&lt;p&gt;对于预测的过程中，我们已有的training set即为规定了y=0与y=1对应的类的contour曲线图，而在进行二分类的过程中可以看成y=0,y=1的contour曲线图的交产生的一条直线&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;GDA示意图&lt;/p&gt;
&lt;h3&gt;与逻辑回归的比较&lt;/h3&gt;
&lt;p&gt;我们发现对于GDA是产生一条分割的边界线，而对于逻辑回归我们也是产生一条分割线，自然而然的想要考虑在GDA中  $P(y|x,\theta)$  计算出来是多少。&lt;/p&gt;
&lt;p&gt;由如下的数学推导和几何直观可以发现&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;从我的Problem set 1 的solution to T1/(c)中截出来的&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;手画的图，表示对于y=0,y=1的正态分布在数轴上的投影后P(y|x)的示意图&lt;/p&gt;
&lt;p&gt;即有在GDA中，  $P(y|x,\phi,\mu_0,\mu_1,\Sigma)=\frac{1}{1+e^{-\theta^T x}}$  是一个sigmoid函数，因此可以认** GDA是逻辑回归的一个特例！！！**&lt;/p&gt;
&lt;p&gt;GDA优点是在使用的时候只需要进行计数的操作就可以求解出其参数，而在进行预测的时候也是直接使用Bayes公式即可，相比于逻辑回归计算量大大下降，也不需要** 非常大**的数据集，就可以快速对于数据集的分布有个大体的认识。&lt;/p&gt;
&lt;p&gt;虽然但是GDA对于我们给出的假设** 正态分布**不一定是对的，如果我们把正态分布换成Poisson分布，同样的过程，也可以和逻辑回归进行对应，同样体现了局限性。&lt;/p&gt;
&lt;p&gt;总结以下这篇文章，对于GDA和逻辑回归而言，GDA做出了更多的假设，因此只需要相对比较小的数据集，而且在特定的情况下可能准确率还更高，但是逻辑回归没有告诉世界什么信息，这些信息只有数据集才可以告诉我们，从而需要更大的数据集，但也因此有了更好的鲁棒性。对于** 模型假设的信息，数据集的信息，准确性和鲁棒性**此几者的关系是我们认识这个世界的方法之一，这个世界观才是GDA的真正要领&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:监督学习(三)——简单粗暴的生成式学习算法(2):Naive Bayes classifier</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-3-2-naive-bayes/cs229-supl-3-2-naive-bayes</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-3-2-naive-bayes/cs229-supl-3-2-naive-bayes</guid><description>CS229:监督学习(三)——简单粗暴的生成式学习算法(2):Naive Bayes classifier</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在昨天的文章中(今天早上）中，我们使用GLA方法，并使用了Gaussian假设，做了一个GDA分类器。由于GDA中的x都是连续的，接下来我们要来介绍离散情况下的一个分类系统。&lt;/p&gt;
&lt;h2&gt;Naive Bayes 分类器&lt;/h2&gt;
&lt;h3&gt;模型建立&lt;/h3&gt;
&lt;p&gt;考虑一个场景：我们想要进行一个文本分类的任务，给定一段文本，判断这是不是垃圾邮件（spam)。对于这个问题，我们由于只是要判断是不是垃圾邮件，所以没有必要使用RNN,Transformer来理解文本的内容，而是考虑以下的几个内容&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于文本如何转换成机器可以学习的feature？&lt;/li&gt;
&lt;li&gt;对于feature转换成分类结果是使用什么分类器？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于我们只是进行垃圾邮件的分类，我们考虑将字典（dictionary)上不同的字在邮件上的出现情况看成feature，即为对于字典（建立的方法可以是统计自己的过去的1000封邮件中的最常见的10000词，也可以是直接将英文的常见的10000词搬出来），对于需要分析的邮件  $x^i\in[1,|V|]$  其中|V|是字典的大小，对于字典中的序号为j的词如果在邮件中出现，  $x^i_j$  标记为1，否则为0，于是我们将邮件转换成一个向量。&lt;/p&gt;
&lt;h3&gt;参数估计&lt;/h3&gt;
&lt;p&gt;对于输入  $x^i$  ,由于它是一个大小为  $|V|$  的每一个元素为0，1的向量，因此可以看成是  ${0,1}^n$  的|V|的输入。由于需要计算  $L(\theta)=\Pi^m_{i=1} P(x^i|y^i,\theta)P(y^i|\theta)$  ,对于  $P(y|\theta)$  由于这是一个二分类系统，因此在未知  $P(x^i|y,\theta)$  的情况下可以认为y是一个伯努利分布，于是确定参数之一为  $P(y=1)=\phi_y$  。&lt;/p&gt;
&lt;p&gt;下面需要计算  $P(x^i|y^i)=P(x^i_1,x^i_2,.....x^i_{|V|}|y^i)=P(x^i_1|y^i)P(x^i_2|x_1^i,y^i)...P(x^i_{|V|}|x^i_1,....x^i_{|V|-1},y^i)$&lt;/p&gt;
&lt;p&gt;我们做出一个大胆的假设，即为&lt;strong&gt;Naive Bayes Assumption&lt;/strong&gt;,即为假设  $x^i_j$  互相之间是于  $y^i$  条件独立的，写成数学公式即为&lt;/p&gt;
&lt;p&gt;$P(x^i|y^i)=P(x^i_1,x^i_2,.....x^i_{|V|}|y^i)=P(x^i_1|y^i)P(x^i_2|x_1^i,y^i)...P(x^i_{|V|}|x^i_1,....x^i_{|V|-1},y^i)=P(x_1^i|y^i)P(x_2^i|y^i)...P(x^i_n|y^i)$ 对于每一个  $P(x_j|y)$  我们由于x是只有两个class，使用伯努利分布，即为  $P(x_j=1|y=1)=\phi_{j|y=1},P(x_j=1|y=0)=\phi_{j|y=0}$&lt;/p&gt;
&lt;h3&gt;结论&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;通过以下的推导过程，我们得到结论：&lt;/p&gt;
&lt;p&gt;$P(x=1|y=1)=\phi_{j|y=1}=\frac{\Sigma^m_{i=1}\Sigma^{|V|}&lt;em&gt;{j=1} 1{x_j^i=1,y^i=1}}{\Sigma^m&lt;/em&gt;{i=1} 1{y^i=1}}\  P(x=1|y=0)=\phi_{j|y=0}=\frac{\Sigma^m_{i=1}\Sigma^{|V|}&lt;em&gt;{j=1} 1{x_j^i=1,y^i=0}}{\Sigma^m&lt;/em&gt;{i=1} 1{y^i=0}}\ P(y=1)=\phi_y=\frac{\Sigma^m_{i=1} 1{y=1}}{m}$ 该结论与GDA预测的结果形式类似，对于y=1类的东西的特征提取，都是对于求出** 满足y=1的所有输入的特征的均值，**Naive Bayes Prediction在参数的训练上还是比较容易的。&lt;/p&gt;
&lt;h3&gt;拉普拉斯平滑（laplace smoothing）&lt;/h3&gt;
&lt;p&gt;在以上的情景中，可能会有如下的情况，就是如果在分析一篇邮件的时候，突然出现了一个在字典中没有出现过的词语，比如说是&apos;Harden&apos;,我们在计算参数的时候，由于该词语没有出现过，因此  $#x|y=1,#x|y=0$  的个数都是0，于是有  $\phi_{x|y=1},\phi_{x|y=0}$  都是0，在预测的时候&lt;/p&gt;
&lt;p&gt;$P(y=1|x)=\frac{P(x|y=1)P(y=1)}{P(x|y=1)P(y=1)+P(x|y=0)P(y=0)}$ 分子分母都是0，这个显然不是特别的合理。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，Laplace曾提出过如下想法：假设过去1000天我都能看见太阳升起，那么加上今天的话(太阳升起的概率为1/2）以后太阳升起的概率不低于1000+1/1000+2=1001/1002&lt;/p&gt;
&lt;p&gt;因此我们考虑在计数的时候  $#x|y=0:#x|y=0+1;#x|y=1:#x|y=1+1$  ,这个操作就称为是** Laplace Smoothing。**&lt;/p&gt;
&lt;p&gt;因此可以调整&lt;/p&gt;
&lt;p&gt;$P(x=1|y=1)=\phi_{j|y=1}=\frac{\Sigma^m_{i=1}\Sigma^{|V|}&lt;em&gt;{j=1} 1{x_j^i=1,y^i=1}+1}{\Sigma^m&lt;/em&gt;{i=1} 1{y^i=1}+2}\  P(x=1|y=0)=\phi_{j|y=0}=\frac{\Sigma^m_{i=1}\Sigma^{|V|}&lt;em&gt;{j=1} 1{x_j^i=1,y^i=0}+1}{\Sigma^m&lt;/em&gt;{i=1} 1{y^i=0}+2}\ P(y=1)=\phi_y=\frac{\Sigma^m_{i=1} 1{y=1}}{m}$&lt;/p&gt;
&lt;p&gt;对于Naive Bayes Classifier 有的时候也会称为是（Multi-Varient Bernoulli Event Model)&lt;/p&gt;
&lt;p&gt;对于以上的生成式学习算法的例子NBC和GDA,我们都是给出了一个比较强的假设，在结果看上去也比较的简单，在对于一个复杂的project分析的时候，用** AndrewNg的话来说就是要先用这些简单的方法完成一些quick and dirty work**然后再具体分析。&lt;/p&gt;
&lt;p&gt;下一篇文章讲支持向量机，敬请期待。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229：监督学习（四）——SVM（支持向量机）</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-4-svm/cs229-supl-4-svm</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-4-svm/cs229-supl-4-svm</guid><description>CS229：监督学习（四）——SVM（支持向量机）</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;支持向量机(SVM, support vector machine)是一种全新的模型（形式上），以往的模型都是为了拟合&lt;strong&gt;线性的&lt;/strong&gt; 分界（可能对于GDA模型中两个class的方差取不同值的时候分解线的形状不是直线），SVM可以使用核函数空间中的任何一组基来拟合出任何的&lt;strong&gt;非线性边界&lt;/strong&gt; 分类，与此同时训练的时候也不容易发生过拟合，可以说这款模型的性能称得上是非常的优秀。&lt;/p&gt;
&lt;p&gt;1.hypothesis&lt;/p&gt;
&lt;p&gt;2.loss function and the method&lt;/p&gt;
&lt;p&gt;3.the mathematic process&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;how to prevent overfitting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;5.SMO method to train it.(how to choose the parameters, how to adjust the params)&lt;/p&gt;
&lt;h2&gt;SVM核心概念&lt;/h2&gt;
&lt;h3&gt;中心思想&lt;/h3&gt;
&lt;p&gt;问题：给定一组数据集  ${x^i,y^i},i\in[1,m],y\in{-1,1}$  ，现在需要寻找数据集之间的非线性拟合边界并且对于test_set进行预测。(y的值-1，1是为了后序方便）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Essence:&lt;/strong&gt; 由于我们仍然想要使用线性模型去拟合，再之前，我们使用的基函数都是  $[x_1,x_2,...x_n]$  ,核心思想是构建一组  $[x_1,x_2...x_n,x_1^2,x_1x_2....x_1^3......x_1^n....]$  的基函数，并将问题转换成&lt;strong&gt;高维上的二分类问题&lt;/strong&gt; 再投影到二维平面上，看上去就是非线性曲线边界（所以我们说是形式上）&lt;/p&gt;
&lt;p&gt;示意图如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这是一份我们需要分类的数据，光圈表示边界（理论上长得是一个圆环，待拟合），点表示数据&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;SVM即为投影到高维，然后对于高维的线性拟合，再投影下来&lt;/p&gt;
&lt;h2&gt;响应函数&amp;#x26;损失函数推导&lt;/h2&gt;
&lt;p&gt;我们先考虑对于  $[x_1,x_2,...x_n]$  这一组基函数进行二分类，由于我们对于基函数之间可能维度不同，因此需要采用一种不同的方法来拟合与边界之间的关系。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;响应函数：&lt;/strong&gt; 由于我们仍然是使用线性模型，故响应函数为  $h_{w,b}(x)=w^T x+b$  ，而对于  $\hat{y}=1(h_{\theta}&gt;0),0(otherwise)$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;损失函数推导：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们想要借鉴之前逻辑回归的边界判定方法来对于边界进行评估。逻辑回归中，我们有&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当  $\hat{y}=1$  的时候，  $\theta^T x&gt;&gt;0$  ，当  $\hat{y}=0$  的时候，  $\theta^T x&amp;#x3C;&amp;#x3C;0$  表示模型对于数据的拟合程度比较好（如此取出的边界是比较好的），由此我们对于SVM的损失函数应该有&lt;/p&gt;
&lt;p&gt;当  $\hat{y}=1$  的时候，  $w^Tx+b&gt;&gt;0$  ,  $\hat{y}=-1$  的时候，  $w^T x+b&amp;#x3C;&amp;#x3C;0$  的特性，从而可以设计&lt;/p&gt;
&lt;p&gt;$f_{margin}(x^i,y^i)=y^i(w^Tx+b)$  为损失函数，当f的值比较大的时候说明拟合效果比较好。&lt;/p&gt;
&lt;p&gt;话虽如此，如果我们把所有的图像等比例放大&lt;/p&gt;
&lt;p&gt;$f_{margin}(x^i,y^i)=y^i(2w^Tx+2b),f_{margin}(x^i,y^i)=y^i(20000w^Tx+20000b)$  这两个的分类效果和原本是一样的，故进行归一化，取  $g_{margin}(x^i,y^i)=\frac{y^i(w^Tx^i+b)}{||w||}$  来评估边界的性能。&lt;/p&gt;
&lt;p&gt;2.对于所有的数据，我们的评估函数g(x)再几何角度上可以看成是到每一个数据点到边界的距离，因此对于边界的评估，我们可以用所有的样本的距离的最小值取评估，即为&lt;/p&gt;
&lt;p&gt;$\gamma=min^m_{i=1} \gamma^i,\gamma^i=\frac{y^i(w^T x+b)}{||w||}$&lt;/p&gt;
&lt;h3&gt;损失函数形式化简&lt;/h3&gt;
&lt;p&gt;这一段可能会比较冗长，主要是对于评估函数的等价化化简，下面来细说之。&lt;/p&gt;
&lt;p&gt;我们的损失函数为  $max(\gamma),\frac{y^i(w^Tx^i+b)}{||w||}\geq\gamma$  ，令  $||w|| \gamma=t$  ,则化简为  $max(\frac{t}{||w||}),y^i(w^Tx^i+b)\geq t$  ,由线性性，不妨设t=1,则  $max(\frac{1}{||w||}),y^i(w^Tx^i+b)\geq 1$  ，从而只需要证明  $min(\frac{1}{2}||w||^2),y^i(w^Tx^i+b)\geq 1$&lt;/p&gt;
&lt;p&gt;我们先来补充一点点的** 数学基础**：&lt;/p&gt;
&lt;p&gt;对于  $minf(x),h_i(x)=0,g_i(x)\geq 0$  的问题，由拉格朗日乘数法，考虑&lt;/p&gt;
&lt;p&gt;$L_{\alpha_i,\beta_i}(x)=f(x)+\Sigma_{i=1}^m\alpha_ig_i(x)+\Sigma_{i=1}^n\beta_ih_i(x)$  需要考虑L(x)在** 先&lt;strong&gt;求拉格朗日乘子在定义域上的最大值，&lt;/strong&gt; 然后**求L(x)对于x在x的定义域上的最值，即为  $ans=min_xmax_{\alpha,\beta}L(x)$&lt;/p&gt;
&lt;p&gt;我们考虑什么时候可以交换这两个符号，由** 凸优化理论，**  $min_x max_{\alpha,\beta}L(x)\geq max_{\alpha,\beta}min_xL(x)$  成立当且仅当f，g都为凹函数且h可以写成x的线性组合。&lt;/p&gt;
&lt;p&gt;因此要求L(x)的最小值，我们需要有等号成立（等号显然成立），对于  $min_xL(x)$  就可以使用** 拉格朗日乘数法**，结合max的条件，对于  $L_{\alpha,\beta}(x)$  必然存在  $\alpha^&lt;em&gt;,\beta^&lt;/em&gt;,x^*$  使得&lt;/p&gt;
&lt;p&gt;$\frac{\partial L_{\alpha,\beta}(x^&lt;em&gt;)}{\partial x}=0(1)\ \frac{\partial L_{\alpha,\beta}(x^&lt;/em&gt;)}{\partial \alpha}=0(2)\ \frac{\partial L_{\alpha,\beta}(x^&lt;em&gt;)}{\partial \beta}=0(3)\ g(x^&lt;/em&gt;)\leq0,\alpha^&lt;em&gt;&gt;0(4)\ \alpha^&lt;/em&gt;_ig_i(x^*)=0(5)\  $&lt;/p&gt;
&lt;h3&gt;损失函数化简&lt;/h3&gt;
&lt;p&gt;对原损失函数使用拉格朗日乘数法，得到&lt;/p&gt;
&lt;p&gt;$L_{\alpha,\beta}(x)=\frac{1}{2}||w||^2-\Sigma^m_{i=1}\alpha^i(y^i(w^Tx^i+b)-1)$  ，将KKT条件带入得到&lt;/p&gt;
&lt;p&gt;$\frac{\partial L_{\alpha,\beta}(w^&lt;em&gt;)}{\partial w}=0\Rightarrow w=\Sigma^m_{i=1}\alpha_iy^ix^i\  \frac{\partial L_{\alpha,\beta}(w^&lt;/em&gt;)}{\partial \beta}=0\Rightarrow\Sigma^m_{i=1}\alpha_iy^i=0\ \alpha_i&gt;0(4)\ \alpha^&lt;em&gt;_ig_i(w^&lt;/em&gt;)=0\Rightarrow y^i(w^Tx^i+b)=1\  $&lt;/p&gt;
&lt;p&gt;因此我们只需要拟合参数  $\alpha_i$  (由此我们可以发现SVM的参数大小是和训练数据的量密切相关的),使得&lt;/p&gt;
&lt;p&gt;$max_\alpha\Sigma^m_{i=1}\alpha_i-\Sigma^m_{i=1}\Sigma^m_{i=1}\frac{1}{2}y^iy^j\alpha_i\alpha_j&amp;#x3C;x_i,x_j&gt;$  限制条件为  $\Sigma_{i=1}^m\alpha_iy^i=0,\alpha_i&gt;0$  ,其中  $&amp;#x3C;x_i,x_j&gt;$  为基函数  $x_i,x_j$  之间的内积。&lt;/p&gt;
&lt;p&gt;在预测的时候，有  $h_{\alpha,b}(x)=\Sigma_{i=1}^m\alpha_iy^i&amp;#x3C;x^i,x&gt;+b$  ,由KKT条件有&lt;/p&gt;
&lt;p&gt;$y^i(w^Tx^i+b)=1\Rightarrow w^Tx+b=y^i\Rightarrow b=y^i-\alpha_iy^i&amp;#x3C;x_i,x_i&gt;$&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;核函数（Kernel trick)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;以上的操作都是对于以  $[x_1,x_2,...x_n]$  为基函数的空间进行的线性分类，注意到无论是损失函数还是预测函数我们都是使用基函数的内积去操作的，因此我们只需要建立能计算对于新的基函数  $f_i(x_1,x_2,....x_n)$  两两之间的内积  $&amp;#x3C;f_i,f_j&gt;$  即可，为此我们使用一个叫做核函数的东西。&lt;/p&gt;
&lt;p&gt;设我们的一组基构成的向量为  $\phi(x)=[f_1(x_1,x_2,...x_n)...f_m(x_1,x_2,...x_m)]$  ,由于当我们选择欧氏空间时，内积为  $x^TGx$  ，其中G为其度量矩阵，其计算方式为  $G=[x_1,x_2,...x_n][x_1,x_2,...x_n]^T=I$  ,因此我们仿照即有令  $K(x,z)=\phi(x)^T\phi(z)$  ** 称K(x,z)为核函数**&lt;/p&gt;
&lt;p&gt;举个例子&lt;/p&gt;
&lt;p&gt;例：  $1.K(x,z)=x^Tx,\phi(x)=[x_1,x_2,...x_n]\ 2.K(x,z)=(x^Tz+b)^2,\phi(x)=[x_1^2,x_2^2,..x_n^2,\sqrt{2b}x_1,\sqrt{2b}x_2,...\sqrt{2b}x_n,b]$&lt;/p&gt;
&lt;p&gt;因此如果我们规定了核函数（核函数需要可以写成  $K(x,z)=\phi(x)^T\phi(z)$  ，可以证明，对于任何的半正定矩阵都可以写成核函数的形式），将  $&amp;#x3C;x,z&gt;\Rightarrow K(x,z)$  即可将基所在的空间由n维拓展到任意的想要的维度。&lt;/p&gt;
&lt;p&gt;常见的核函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gaussian 核：  $K(x,z)=exp(-\frac{(x-z)^T(x-z)}{2\sigma^2})$  无穷维空间&lt;/li&gt;
&lt;li&gt;Polynomial核：  $K(x,z)=(x^Tz+1)^n$  多项式空间&lt;/li&gt;
&lt;li&gt;线性核：  $K(x,z)=x^Tz$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;为什么我们需要使用核函数&lt;/strong&gt; ？对于核函数由以上的形式可以发现，如果对于输入  $x^i=[x^i_1,x^i_2,...x^i_n]$  ，而基为m维的，那么对于基的计算就需要O(m)的复杂度，于是对于  $K(x,z)=\phi(x)^T\phi(z)$  的计算O(m)的复杂度，而如果是使用了核函数的话，在计算的时候，  $x^Tz$  的计算只需要O(n）的复杂度，从而  $K(x,z)$  的计算只需要O(n)的复杂度。&lt;/p&gt;
&lt;p&gt;比如对于Polynomial核而言，如果是不使用核函数，就需要  $O(n^d)$  的复杂度，效果非常的明显。&lt;/p&gt;
&lt;p&gt;综上所述，我们有了&lt;strong&gt;SVM&lt;/strong&gt; 的评估函数以及响应函数&lt;/p&gt;
&lt;p&gt;$1.max_\alpha\Sigma^m_{i=1}\alpha_i-\Sigma^m_{i=1}\Sigma^m_{i=1}\frac{1}{2}y^iy^j\alpha_i\alpha_j K(x_i,x_j),\alpha_i&gt;0,\Sigma^m_{i=1}\alpha_iy^i=0\ 2.h(x)=\Sigma^m_{i=1}\alpha_iy^iK(x^i,x)-\frac{1}{m}\Sigma^m_{i=1}(y^i-\alpha_iy^iK(x_i,x_i))$&lt;/p&gt;
&lt;p&gt;以上的情况都是对于数据集分类情况比较良好的情况(如左图），而对于右图(不可分隔的情况），Variance就容易变得非常的大。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;不可分隔的数据集的一个例子，手画，勿喷&lt;/p&gt;
&lt;p&gt;为了解决过拟合噪声的问题，我们需要对于进行正则化，在本题中，由于距离的定义是与&lt;strong&gt;边界之间的距离&lt;/strong&gt; $\frac{y^i(w^Tx^i+b)}{||w||}$  并且是以1为单位的，因此我们只需要对于每一项的的距离用  $1:1-\zeta_i$  去代替即可。&lt;/p&gt;
&lt;p&gt;即为  $min(\frac{1}{2}||w||^2+C\Sigma^m_{i=1}\zeta_i^2),y^i(w^Tx^i+b)\geq 1-\zeta_i$&lt;/p&gt;
&lt;p&gt;使用同样的方式进行化简，我们即有** 正则化后的SVM模型**&lt;/p&gt;
&lt;p&gt;$1.max_\alpha\Sigma^m_{i=1}\alpha_i-\Sigma^m_{i=1}\Sigma^m_{i=1}\frac{1}{2}y^iy^j\alpha_i\alpha_j K(x_i,x_j)\ 0&amp;#x3C;\alpha_i&amp;#x3C;C,\Sigma^m_{i=1}\alpha_iy^i=0\ 2.h(x)=\Sigma^m_{i=1}\alpha_iy^iK(x^i,x)-\frac{1}{m}\Sigma^m_{i=1}(y^i-\alpha_iy^iK(x_i,x_i))$&lt;/p&gt;
&lt;p&gt;而且KKT条件变成了&lt;/p&gt;
&lt;p&gt;$\alpha_i=0\Rightarrow y^i(w^Tx^i+b)\geq 1\ \alpha_i=C\Rightarrow y^i(w^Tx^i+b)\leq 1\ 0&amp;#x3C;\alpha_i&amp;#x3C;C\Rightarrow y^i(w^Tx^i+b)= 1$&lt;/p&gt;
&lt;p&gt;而该KKT条件就是损失函数收敛的条件，即可用来进行训练。&lt;/p&gt;
&lt;h3&gt;参数训练（SMO,sequential minimal optimization)&lt;/h3&gt;
&lt;p&gt;接下来就是如何训练这些  $\alpha_i$  了，我们仍然想要使用梯度下降法，但是这道题目中有两个限制条件，因此我们不能直接使用原来的梯度下降，我们使用类似** 高中数学竞赛中的“调整法”的思路**，每一次选择两个参数  $\alpha_i,\alpha_j$  进行调整，直到全部满足KKT条件&lt;/p&gt;
&lt;p&gt;SMO步骤&lt;/p&gt;
&lt;p&gt;Step1:选择参数  $\alpha_i,\alpha_j$  。&lt;/p&gt;
&lt;p&gt;Step2:对于  $\alpha_i,\alpha_j$  进行调整，控制  $\Sigma^m_{i=1}\alpha_iy_i=0$  不变，调整  $\alpha_iy^i+\alpha_jy^j=-\Sigma_{other}\alpha_ky^k=c$  则有  $\alpha_i y^i+\alpha_jy^j=c\Rightarrow \alpha_i=y^i(c-\alpha_jy^j)$&lt;/p&gt;
&lt;p&gt;损失函数  $W=\Sigma^m_{i=1}\alpha_i-\Sigma^m_{i=1}\Sigma^m_{i=1}\frac{1}{2}y^iy^j\alpha_i\alpha_j K(x_i,x_j)$  ,将调整之后的结果带入，结果为&lt;/p&gt;
&lt;p&gt;$W=\alpha_j+y^i(c-\alpha_jy^j)+\Sigma_{other} \alpha_k-\frac{1}{2}(y^iy^i (y^i(c-\alpha_jy^j)^2K(x_i,x_i+y^jy^j(\alpha_j)^2K(x_j,x_j)+2y^iy^jy^i(c-\alpha_jy^j)\alpha_jK(x_i,x_j)+2(y^iy^i(c-\alpha_jy^j)K(x_i,x_k)+y^j\alpha_jK(x_j,x_k))\Sigma_{other} \alpha_k+other)\ =\alpha_j+y^i(c-\alpha_jy^j)-\frac{1}{2}((c-\alpha_jy^j)^2K(x_i,x_i)+(\alpha_j)^2K(x_j,x_j)+2y^j(c-\alpha_jy^j)\alpha_jK(x_i,x_j)+2((c-\alpha_jy^j)K(x_i,x_k)+y^j\alpha_jK(x_j,x_k))\Sigma_{other} \alpha_k+other)$&lt;/p&gt;
&lt;p&gt;$\dfrac{\partial W}{\partial \alpha_j}=1-y^iy^j-\frac{1}{2}(2y^j(\alpha_jy^j-c)K(x_i,x_i)+2\alpha_jK(x_j,x_j)-4\alpha_jK(x_i,x_j)+\Sigma_{other}\alpha_k(-y^jK(x_i,x_k)+y^jK(x_j,x_k)))=0\ $&lt;/p&gt;
&lt;p&gt;这是关于  $\alpha_j$  的一元方程，从而可以接的  $\alpha_j=...$ ,记成A。&lt;/p&gt;
&lt;p&gt;结合调整之后需要满足的限制条件  $\alpha_i^{new},\alpha_j^{new} \in[0,C]$  ，我们对于  $L&amp;#x3C;\alpha_j&amp;#x3C;H$  ,必须满足  $y^i!=y^j,L=max(0,\alpha_j-\alpha_i),H=min(C,C+\alpha_j-\alpha_i)\ y^i=y^j,L=max(0,\alpha_i+\alpha_j-C),H=min(C,\alpha_i+\alpha_j)$&lt;/p&gt;
&lt;p&gt;从而结合限制条件之后，  $\alpha_i=H  \ ,\alpha_j&gt;H\ =A,L&amp;#x3C;\alpha_j&amp;#x3C;H\ =L, \alpha_j&amp;#x3C;H$&lt;/p&gt;
&lt;p&gt;示意图如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;SMO示意图&lt;/p&gt;
&lt;p&gt;Step3:当所有的参数满足KKT条件或者可以看成是kkt条件时,即为&lt;/p&gt;
&lt;p&gt;$\alpha_i=0\Rightarrow y^i(w^Tx^i+b)\geq 1\ \alpha_i=C\Rightarrow y^i(w^Tx^i+b)\leq 1\ 0&amp;#x3C;\alpha_i&amp;#x3C;C\Rightarrow y^i(w^Tx^i+b)= 1(|y^i(w^Tx^i+b)-1|&amp;#x3C;10^{-5})$&lt;/p&gt;
&lt;p&gt;的时候，可以认为收敛&lt;/p&gt;
&lt;p&gt;以上我们将SVM的损失函数，评估函数与训练过程给简略的描述了一遍，对于SVM的过程如此复杂的有一部分原因是在有限制条件的时候无法使用传统的距离函数与梯度下降，本方法则为以上的情况提供了一个新的解决思路。&lt;/p&gt;
&lt;p&gt;虽然如此，在设计模型的时候，仍然是想要往** 线性回归&lt;strong&gt;上面去思考，而在本题中是通过重新构造了一个评估函数，并使用&lt;/strong&gt; 核函数去作为高维到低维的桥梁。&lt;strong&gt;同样是借用了&lt;/strong&gt; 逻辑回归&lt;strong&gt;的思路，从&lt;/strong&gt; 距离的度量，&lt;strong&gt;到&lt;/strong&gt; 损失函数的构建，&lt;strong&gt;到&lt;/strong&gt; 数学推导，&lt;strong&gt;到&lt;/strong&gt; 最后的模型训练，&lt;strong&gt;将空间换成了&lt;/strong&gt; 有限制的无穷维的空间，清晰明了，有解释性的推导&lt;strong&gt;让我们好好品味到了&lt;/strong&gt; 机器学习的美。**&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:监督学习（五）——神经网络训练与架构</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-5-nn/cs229-supl-5-nn</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-supl-5-nn/cs229-supl-5-nn</guid><description>CS229:监督学习（五）——神经网络训练与架构</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在之前的模型中，我们都是有一堆的输入，输入到一个函数当中，得到对于概率的响应函数。但是这些都是只经过一个函数，在这个过程中用到了非常强的假设，对于复杂的模型的拟合效果自然不是特别的好。&lt;/p&gt;
&lt;p&gt;在Lecture10，11中我们学习了关于深度学习的基础——&lt;strong&gt;神经网络&lt;/strong&gt; 。包括神经网络中的神经元的架构，预测（Forward Propagation前向传播）以及训练参数（Backward Propagation反向传播），训练中的常见问题以及解决方法，以及一些有趣的想法&lt;/p&gt;
&lt;h2&gt;神经网络基本元素&lt;/h2&gt;
&lt;p&gt;以我们之前学过的逻辑回归为例，我们给了一张  $64\times 64\times 3 $  的图片，想要训练一个模型，判定这个图片中有没有猫。之前我们做的是  $h_{\theta}(x)=sigmoid(\theta^T x)=sigmoid(w^Tx+b)$ 。输出的时候使用这个函数去得出输入的东西有猫的概率，若概率大于0.5，则输出1，反之为0。训练的时候我们使用  $J(\theta)=\Sigma^m_{i=1}logP(y^i|x^i,\theta)$  作为损失函数去计算去拟合参数。&lt;/p&gt;
&lt;p&gt;进一步的，我们将这个过程看成对于图片先输入，然后参数输入到  $w^T\alpha+b$  的步骤，再通过sigmoid函数，最后输出的步骤，&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;神经元：&lt;/strong&gt; 输入的参数通过一个线性层，然后用一个激活函数作用，得到一个输出。这就是一个神经元，数学表示即为  $y=f(w^TX+b)$  ,其中w称为权重，而b为偏置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;层：&lt;/strong&gt; 对于层之中的元素无连接关系，而对于相邻的层之间为两两连接的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输入输出层：&lt;/strong&gt; 特殊的神经元（至少我是这样理解的），输入层（input layer)可以看成是一个一对一的，激活函数为一次函数，无偏置的一层神经元，将输入传递到网络内。输出层（output layer)中的每一个神经元都会输出一个相应的结果。而隐藏层则为其余的所有的层。&lt;/p&gt;
&lt;p&gt;一个简单的神经网络如下图，这是一个输入+3个隐藏层+输出的一个神经网络。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;a picture about the Neuron Network&lt;/p&gt;
&lt;p&gt;为了方便起见，对于输入我们记成一个矩阵  $X=(x_1,x_2,...x_n)$  ,对于第i层的输出为  $a^i=(a^i_1,a^i_2,...a^i_{n_1})$  为第一层所有的矩阵的输出组成的矩阵，对于第i层的权重与偏置组成矩阵和向量  $w^i,b^i$  因此对于这个网络我们有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$z^1=w^1X+b^1,a^1=\sigma(z^1)$&lt;/li&gt;
&lt;li&gt;$z^2=w^2a^1+b^2,a^2=\sigma(z^2)$&lt;/li&gt;
&lt;li&gt;$z^3=w^3a^2+b^3,a^3=\sigma(z^3)$&lt;/li&gt;
&lt;li&gt;$\hat{y}=a^3$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果我们已经得到了所有的参数之后，对于需要预测的向量  $t=(t_1,t_2,...t_n)$  而言，只需要输入到神经网络中，就有输出  $\hat{y}=\sigma(w^3\sigma(w^2\sigma(w^1t+b^1)+b^2)+b^3)$  即为所求，对于每一层的参数不断往前传递的过程我们称为前向传播(Forward Propagation)&lt;/p&gt;
&lt;h2&gt;神经网络参数训练&lt;/h2&gt;
&lt;p&gt;我们参数训练仍然是参考之前的线性回归和逻辑回归&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;损失函数:&lt;/strong&gt; 若结果是离散的，则其损失函数为  $J(\theta)=-\Sigma^m_{i=1}y^ilog(softmax(\hat{y}^i)),softmax(\hat{y}^i)=\dfrac{e^{\hat{y}^i}}{\Sigma e^{z_k}}$  ,而如果是连续的，那么其损失函数为  $J(\theta)=\dfrac{1}{2}|y-\hat{y}|^2$  。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;训练原理：&lt;/strong&gt; 仍然为梯度下降，对于网络中的参数  $\theta$ ,更新原理仍然为  $\theta:=\theta-\alpha\dfrac{\partial J(\theta,\theta_{other})}{\partial \theta}$  ,只是由于神经网络的特殊的架构，我们可能会使用不同的batch批次去训练（后面再说）&lt;/p&gt;
&lt;h2&gt;反向传播（Backward propagation）&lt;/h2&gt;
&lt;p&gt;在梯度下降的过程中，我们需要求解  $\dfrac{\partial J(\theta)}{\partial \theta}$  ，但是由于神经网络的特点，参数求导并不像以往的回归模型中直接求导。而借由链式法则求解时，我们又发现在求导的过程中对于不同参数的求解过程中有较多可以存储的地方，从而可以将误差进行传播。&lt;/p&gt;
&lt;p&gt;以对权重求导为例，我们有&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以发现，对于每一层的参数求导的时候对于不同层之间的  $\dfrac{\partial J}{\partial z^i}$  都是从  $z^n\Rightarrow z^{n-1}...\Rightarrow z^1$  （由此称为时反向传播)。&lt;/p&gt;
&lt;p&gt;使用以上的规则，对于&lt;strong&gt;神经网络的参数训练步骤&lt;/strong&gt; 如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step1:&lt;/strong&gt; 在上一个batch中会存储下所有参数的值，  $z^i,a^i,w^i,b^i,X，\hat{y},i\in{[1,n_{layer}]}$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step2:&lt;/strong&gt; 首先计算  $\dfrac{\partial J}{\partial z^n}$  ,然后由反向传播根据  $\dfrac{\partial J}{\partial z^{n-1}}=\dfrac{\partial J}{\partial z^n}\dfrac{\partial z^n}{\partial a^{n-1}}\dfrac{\partial a^{n-1}}{\partial z^{n-1}}$  。&lt;/p&gt;
&lt;p&gt;由于对于  $\dfrac{\partial z^n}{\partial a^{n-1}}，\dfrac{\partial a^{n-1}}{\partial z^{n-1}}$  的表达式我们都直到，因此只需要将上一个batch中的的结果带入即可&lt;/p&gt;
&lt;p&gt;同理可以计算出  $\dfrac{\partial J}{\partial z^n},\dfrac{\partial J}{\partial z^{n-1}},....\dfrac{\partial J}{\partial z^1}$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step3:&lt;/strong&gt; 对于需要求解的参数  $\dfrac{\partial J}{\partial w^i}=\dfrac{\partial J}{\partial z^i}\dfrac{\partial z^i}{\partial w^i},\dfrac{\partial J}{\partial b^i}=\dfrac{\partial J}{\partial z^i}$  由于表达式已知，因此可以直接求解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step4:&lt;/strong&gt; 使用  $\theta:=\theta-\alpha\dfrac{\partial J(\theta,\theta_{other})}{\partial \theta}$  对于所有的参数进行更新，并记录  $z^i_{new},a^i_{new},w^i_{new},b^i_{new},X，\hat{y}&lt;em&gt;{new},i\in{[1,n&lt;/em&gt;{layer}]}$&lt;/p&gt;
&lt;p&gt;在实际使用中，我们会将整个数据集合分成若干个batch进行输入，每一次输入的时候会使用上一个batch存储的数据，使用这一次的数据去更新。&lt;/p&gt;
&lt;p&gt;这样可以有效的节约内存，但是会导致loss是按照锯齿形状下降，这种方法称为batch-algorithm&lt;/p&gt;
&lt;h2&gt;常见问题以及相应的对策&lt;/h2&gt;
&lt;h3&gt;常见的损失函数&lt;/h3&gt;
&lt;p&gt;之前我们见过了sigmoid函数，线性函数，在实际中还有一些别的函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ReLU函数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表达式  $ReLU(x)=x(when\ x&gt;0),0 (otherwise)$  ,&lt;/p&gt;
&lt;p&gt;对于导数值  $ReLU&apos;(x)=0(when\ x &amp;#x3C;0),1 (otherwise)$&lt;/p&gt;
&lt;p&gt;其特点是计算简单使用** 方便**，且其导数的值正好为1, ** 不容易发生梯度消失或爆炸**的现象，但是缺点是几何意义不是特别的好&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sigmoid函数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表达式  $Sigmoid(x)=\dfrac{1}{1+e^{-x}}$  ,且  $Sigmoid&apos;(x)=\sigma(x)(1-\sigma(x))$&lt;/p&gt;
&lt;p&gt;其特点是可以将整个实数轴上的东西压缩到（0，1）上，可以进行** 归一化**，但是缺点是导数容易发生** 梯度消失**的情况。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;tanh函数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;表达式为  $tanh(x)=\dfrac{e^z-e^{-z}}{e^z+e^{-z}},tanh&apos;(x)=1-tanh^2(x)$&lt;/p&gt;
&lt;p&gt;同样的，其特点是可以将实数轴的东西压缩到** （-1，1）&lt;strong&gt;上，缺点也是容易发生&lt;/strong&gt; 梯度消失**的情况&lt;/p&gt;
&lt;p&gt;以上图像如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;sigmoid&amp;#x26;tanh&lt;/p&gt;
&lt;h3&gt;梯度消失/爆炸以及对策&lt;/h3&gt;
&lt;p&gt;由于我们在计算梯度的时候，对于深度神经网络常常会是几十个东西乘在一起，但是我们知道  $2^{64}$  直接炸掉longlong了，因此我们要对此做出一些对策&lt;/p&gt;
&lt;p&gt;** Method1**:使用ReLU作为激活函数，减少使用sigmoid和tanh函数&lt;/p&gt;
&lt;p&gt;** Method2**:使用合适的初始化，其原则是使得梯度尽可能的接近于1&lt;/p&gt;
&lt;p&gt;结合  $z=w_1x_1+w_2x_2+...w_nx_n$  为倒数第一层的一个神经元，总共有n个输入，那么对于z希望在1附近，就需要  $w_i$  在  $\frac{1}{n}$  附近，从而对于第l层我们有  $w_i\approx\frac{2}{n^{m-(l-1)}}$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple Initialization&lt;/strong&gt; :  $W_i^l=np.random.randn(shape)*np.sqrt(\frac{2}{n^{l-1}})$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xavier Initialization&lt;/strong&gt; :改成  $\sqrt{\dfrac{1}{n^{l-1}}}$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;He Initialization&lt;/strong&gt; :改成  $\sqrt{\dfrac{2}{n^l+n^{l-1}}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上就是神经网络的基本内容，包括架构，预测过程，损失函数以及梯度求解中的反向传播，掌握好这些，便可以为之后理解更加复杂的神经网络结构打下基础，对整个世界有更加清晰的认识。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229: 无监督学习（一）：从聚类到成分分析——K-means、PCA 与 ICA</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-unsupl-1-clust-pca-ica/cs229-unsupl-1-clust-pca-ica</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-unsupl-1-clust-pca-ica/cs229-unsupl-1-clust-pca-ica</guid><description>CS229: 无监督学习（一）：从聚类到成分分析——K-means、PCA 与 ICA</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在之前的课程中，我们学习了当数据集为  $(x^i,y^i)$  的标签数据时的监督学习以及一些优化模型的思想。而在实际生活中，有这样的情况：训练一个大模型的时候，我们只有一个语料库，里面没有说对于《数学分析》标签为1的情况，对于数据集为  $(x^i)$  时进行训练与预测，我们称之为无监督学习。接下来我们将会学习一些无监督学习的方法。&lt;/p&gt;
&lt;p&gt;对于无监督学习，我们会使用概率学习（Factor-analysis,Mixture of Gaussian）以及无概率学习(PCA,K-means,ICA)两种模式，以及处理概率模型时的一种常见模型：EM算法。这些模型中的自我迭代，特征值，如何做出假设这些想法为以后我们思考问题提供了一种思考方式&lt;/p&gt;
&lt;h2&gt;K-means聚类算法&lt;/h2&gt;
&lt;p&gt;对于之前我们使用过softmax以及EM处理过多分类以及非线性边界问题，但是当时的训练数据集都有数据的标签，而现在我们给定了一组数据  $(x^1,x^2,...x^n)$  想要将其分成k类。而k-means聚类算法是通过&lt;strong&gt;聚类中心学习&lt;/strong&gt; ，通过&lt;strong&gt;距离&lt;/strong&gt; 因素去预测。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;k-means 具体步骤&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于数据  $(x^1,x^2,...x^m),x^i\in R^n$  ，随机取聚类中心  $(\mu^1,\mu^2,...\mu^k)$  为  $R^n$  上的任意k个点&lt;/li&gt;
&lt;li&gt;将每一个  $x^i$  的标签记为与其最近的聚类中心的类  $c^i$  ,即为  $c^i=argmin_{j}||x^i-\mu_j||^2$&lt;/li&gt;
&lt;li&gt;更新数据：将聚类中心位置  $\mu_j$  更新为其类中所有的点的中心，即为  $\mu_j:=\dfrac{\Sigma_{i=1}^m1{c^i=j}x^i}{\Sigma_{i=1}^m1{c^i=j}}$&lt;/li&gt;
&lt;li&gt;不断重复以上三个步骤&lt;/li&gt;
&lt;li&gt;预测的时候，对于数据  $x$  ，预测值  $c=argmin_{j}||x-\mu_j||^2$  即为所求&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;k-means几何直观上就是我们对于理论上的最佳的分类方式，我们通过迭代一定会让我们分类的中心点不断趋近于每一个理想分类的中心，而使用k-means一定是收敛的，因为  $J(c,\mu)=\Sigma^m_{i=1}||x^i-\mu_{c^i}||^2$  是单调递减的，从而一定收敛&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;k-means&lt;/p&gt;
&lt;p&gt;k-means的原则是对于每一个点的分类只取决距离它最近的聚类中心，每一个点的分类是确定的，而不是通过概率，这也说明k-means在使用的时候&lt;strong&gt;较难与其余的模型结合，拓展性较差&lt;/strong&gt; ，但是通过距离去迭代中心的思想是有一定借鉴性的。&lt;/p&gt;
&lt;p&gt;以上都是&lt;strong&gt;分类&lt;/strong&gt; 问题，而我们常常会涉及到&lt;strong&gt;component analysis&lt;/strong&gt;,即为对于一组数据如何找到组成它的重要元素，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于脑电波提取的时候，大量的传感器会传来若干组曲线，我们想要找到这些曲线是由那些部分组成，比如心脏跳动，眼皮跳动之类的，这就是找到相互独立的部分Independent component analysis(ICA）&lt;/li&gt;
&lt;li&gt;如果我们在房间里面放了若干个传感器来探测温度，我们如何从这么多的数据中去抽象出来温度的曲线？这就需要使用类似与数据压缩的技术：Principal component analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两者一个是为了&lt;strong&gt;还原原本的数据&lt;/strong&gt; ，一个是为了压缩数据，&lt;strong&gt;去除噪声&lt;/strong&gt; ，共同点都是原本的数据都是混合的，而且提升了数据处理之后的无相关性，实际中都是非常的有用的。&lt;/p&gt;
&lt;h2&gt;PCA(Principal component analysis)&lt;/h2&gt;
&lt;p&gt;所谓的PCA，实际上就是找到数据的子空间并且通过一定的处理将数据维度减少。就像你在一个校园里面各个角落放了1000个温度传感器，你想要找到这些温度曲线是由太平洋气流，工地施工，学生活动这些子空间构成的，希望将找到这些子空间。&lt;/p&gt;
&lt;p&gt;一看到子空间，如果你线性代数学的比较好的话，对于一个正交矩阵的特征值以及n个特征向量（考虑Schmit正交化后的），每一个向量都可以分解成这些特征向量的线性组合，而对于特征值则代表了矩阵在这个方向上的缩放效应，如果特征值越大，说明对于一个向量在特征向量上投影占比越大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从信息的角度去看&lt;/strong&gt; ，就是特征值越大，这个特征向量所占有的信息就越多，从而应该被提取出来。如此一来，应用到原本的案例中，就是对于测试数据集，我们找到最大的k个特征值(计算重数)，使用对应的特征向量去进行预测，而别的特征向量对应的维度我们则认为是噪声。这就是PCA的基本原理。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;PCA&lt;/p&gt;
&lt;p&gt;当然，这些也只是感性的认识，具体的&lt;strong&gt;数学证明&lt;/strong&gt; 如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;PCA Prooving&lt;/p&gt;
&lt;p&gt;于是我们只需要使用k个最大的特征向量去作为k-dimensional line的一组基即可。&lt;/p&gt;
&lt;p&gt;总结而言PCA即为（1）预处理归一化 （2）求解矩阵  $\Sigma=\frac{1}{m}\Sigma^m_{i=1}x^i{x^i}^T$  的特征值，将对应的特征向量作为一组基 （3）  $\hat{y}=x^Tu$  作为预测&lt;/p&gt;
&lt;p&gt;在这一过程中我们仍然是通过距离这一个要素去作为考量单位为，只是不是考虑与点之间的距离，而是最大化与k-dimensional line 的距离&lt;/p&gt;
&lt;h2&gt;ICA(Independent component analysis)&lt;/h2&gt;
&lt;p&gt;考虑一个场景，对于两个人同时对着面前的麦克风讲话，但是这个麦克风比较低端，没有除杂音设备，因此会将自己面前这个人以及远处的那个人的声音全部录进去，我们的任务就是将这两个声音分开，得到两个独立的声源。&lt;/p&gt;
&lt;p&gt;解决这个问题，由于是两个独立的声源以及录音源，可以假设&lt;strong&gt;对于每一个录音源记录的声音是声源的线性组合&lt;/strong&gt; 。设录音得到的数据为  $x^i,i\in[1,T]$  ,而对于实际上的讲话的人为  $s^i,i \in [1,T]$  ,于是有  $x=As=W^{-1}s,s=Wx$  。&lt;/p&gt;
&lt;p&gt;仍然是希望使用&lt;strong&gt;MLE&lt;/strong&gt;,即为  $P(s)=\Pi^T_{i=1} P_s(s^i)$  ，且我们知道  $P(x)$ 以及x与s之间的变换关系&lt;/p&gt;
&lt;p&gt;我们假设对于声源x在每一个时刻的声音的概率函数F(x)为sigmoid函数，即有  $g(x)=\sigma(x)(1-\sigma(x))$  ,由概率论的知识，由于有  $s=Wx$  ,有&lt;/p&gt;
&lt;p&gt;$g(x)=P_s(Wx)|W|$  (换元，通过概率分布函数求导即可)&lt;/p&gt;
&lt;p&gt;从而有  $P(x^i)=(\Pi^n_{j=1}g(w_j^Tx))|W|\Rightarrow MLE:l(W)=\Sigma^m_{i=1}log((\Pi^n_{j=1}g(w_j^Tx))|W|)$&lt;/p&gt;
&lt;p&gt;然后对于参数W使用随机梯度下降即可。&lt;/p&gt;
&lt;p&gt;ICA即为做出了** 线性组合**这个假设，并对于原始数据进行了一定的假设，得出了分离之后的数据的结果。&lt;/p&gt;
&lt;p&gt;以上就是对于无监督学习中的无概率学习，可以发现，对于无监督学习需要做出更强的假设，在无概率学习中是以** “将距离作为衡量标准”作为额外的信息**进行输入，对于K-means以及PCA都是基于此的，而对于ICA看上去和PCA类似都是对于数据的处理，但是本质上却是一个概率论的问题。在这一块中的距离假设以及ICA进行预处理的方法，都是挺有启发性的。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:Python基础用法及常见库(numpy,matplotlib)常见函数总结</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-python-basics-numpy-matplotlib/cs229-python-basics-numpy-matplotlib</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-python-basics-numpy-matplotlib/cs229-python-basics-numpy-matplotlib</guid><description>CS229:Python基础用法及常见库(numpy,matplotlib)常见函数总结</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;经过长达总时长24h的努力，终于成功的把CS229 Problem Set 1中5道题目给做完了，完成这些题目也是让我略微熟悉了一下python,文件操作和ML中常见的库(numpy,matplotlib)。首先我先来总结一下在我做这些题目中感觉比较常见（容易混淆的）Python及库函数的用法。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Python基础用法&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;** 基本逻辑结构**&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;** if语句(常见）**&lt;/li&gt;
&lt;li&gt;** 循环：**&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;for i in range(n):
while (condition):
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;for 和while是最为常见的操作，对于从0遍历到n-1的时候，我们一般会使用range，而对于while而言个人习惯于把停止条件放在循环里面&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;enumerate用法：如果我们有一个列表/数组/元组，enumerate(array/...)会返回在array里面的元素以及对应的序号例如&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;fruits=[1,2,3,4,5,6]
for index, fruit in enumerate(fruits):
    print(index, fruit)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;遍历一个列表/数组里面的所有元素：&lt;/strong&gt; 直接在in之后写上相应的数组&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;students=[ &apos;aaa&apos; , &apos;bbb&apos; ,&apos;ccc&apos;]
for  student in students:
    print(student)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;函数&amp;#x26;类调用：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;重点在于掌握函数参数的调用以及default arguments(初始默认的函数参数的设置）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def power(v,p=2):
    return v**p
print(power(10),power(10,3))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则输出是100和1000，对于这个求幂次的函数中如果p没有输入，则默认值为2，否则为3（&lt;em&gt;&lt;strong&gt;在机器学习debug的时候非常容易忽略&lt;/strong&gt;&lt;/em&gt;）&lt;/p&gt;
&lt;p&gt;类的结构一般为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class LogisticRegression(Father_class):
    def __init__(self, parameters_init):
         self.parameters=parameters_init
    
    def function1(....):
        ....
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中Father_class为继承类，会继承父类中的参数和内部的函数，而对于类内部的参数我们使用self.parameters,(和c语言类中的参数一样）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;***注意对于参数的初始化！***下面是一个小小的错误（让人非常的烦躁）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;class LogisticRegression(LinearModel):
     def __init__(self,parameters):
          self.theta=None
     def fit(self,x_train,y_train):
          self.theta=self.theta+0.01*x_train.dot(y_train-self.theta.T.dot(x_train))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果直接运行的话会报错！因为对于self.theta=None并没有把self.theta像c语言一样变成0（False)，因此我们需要初始化&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;self.theta=np.zeros(x_train.shape[1])# we assume that it is a Linear-Model
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Python中主要数据结构&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;int,float,char...这几个非常常见的就掠过了&lt;/li&gt;
&lt;li&gt;string:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;字符串的类似于list的性质（这个在通修的C语言课上应该是常识）&lt;/li&gt;
&lt;li&gt;字符串的分割，粘贴：对于字符串的分割，粘贴在文本的预处理，各种地址的统一化操作中是非常常用的，常见的操作有分割（split,strip)和粘贴（+）&lt;/li&gt;
&lt;li&gt;字符串中加入变量：使用f&apos;str{parameters}&apos;的操作，或者使用‘str{}’.formet(...)虽然个人更加喜欢前者（easy)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;str=&apos;           123,456        &apos;
str_new=str.strip()#删除字符串头尾的空格以及空行
str1,str2=str.split(&apos;,&apos;)#按照括号里面的东西将字符串进行分割
str3=str1+&apos;89&apos;+str2 #对于字符串的粘贴我们只要用&apos;+&apos;将一堆东西连起来就可以了
num=5
str4=f&apos;D:/File/problem_{num}.png&apos; #对于将变量加到字符串里面的操作
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.list:&lt;/p&gt;
&lt;p&gt;对于list的一般的操作，list的定义，元素查找，对于加入，删除元素，list之间的连接这个和C语言非常相似，对于python重点的是几个特殊用法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&apos;:&apos;以及负数：对于&apos;:’我的理解是&apos;从...到’的省略，而对于列表中的负数，表示从列表最后一个元素记为-1，每往左一个为-1，比如如下的例子&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;lis=[1,2,3,4,5,6,7]
lis[:5]#为[1,2,3,4]
lis[5:-1]#为[4,5,6,7]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;列表中的循环&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于python的自由的语言环境，里面的操作也相对自由，在定义列表的时候可以通过列表里面的加上循环&amp;#x26;选择来简化我们的过程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;list_square=[i**2 if i%2==0 else i** 3 for i in range(100)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Numpy重要用法：关于矩阵&lt;/h2&gt;
&lt;p&gt;numpy虽然有非常多的函数以及别的操作，但个人感觉numpy最为重要的就是里面的矩阵结构，numpy中包含众多的矩阵（向量）的操作（你在学习线性代数的时候学过的结构在numpy中几乎都有对应的函数，下面我来简介几个最为常用的操作&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;numpy的使用方法：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import numpy as np
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.numpy矩阵和向量的初始化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于向量是基于一个一维的数组生成的，而对于矩阵&lt;strong&gt;必须&lt;/strong&gt; 通过二维的数组生成,方法都是使用np.array&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;array_1d=np.array([1,2,3])
array_2d=np.array([[1,2,3],[4,5,6]])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与此同时，与线性代数中，向量不可以想当然的认为是一个大小为n*1的矩阵，因此如果你想要对于所有的东西变成矩阵去操作的时候（虽然没有任何必要，因为对于相乘可以用同样的东西）需要使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;array_1d_new=np.array([array_1d])
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;矩阵和向量大小的提取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于矩阵是使用A.shape(),将会返回一个列表，而对于向量的大小为使用v.size&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a=[[1,2],[3,4]]
a.shape()#会输出一个为[2,2]的例子
v=[1,2,3,4]
v.size()#会返回4
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;特殊的初始化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于想要生成一个全为0，1的矩阵以及向量，我们可以使用一些特殊的函数,方法为np.zeros(n/(m,n))&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a=np.zeros(n)#生成一个大小为n的全部为1向量
a=np.ones((m,n))# 生成一个大小为m*n的全部是1的矩阵
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.矩阵的运算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单个矩阵的运算：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于单个矩阵的运算，比如整体矩阵内部所有元素开根号，求exp，求sin,我们直接使用np.function()就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B=np.exp/sqrt/sin/cos/...(A)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;多个矩阵之间的运算&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;矩阵与单个实数的乘法和加法：直接做就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A=[[1,2],[3,4]]
A+5,A*5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;矩阵相应元素做乘法：直接写乘号**，在这里要特别注意对于矩阵的乘法运算矩阵的大小要相等！！！** 111&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A,B=[[1,2],[3,4]],[[1,2],[3,4]]
A*B # 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;矩阵的乘法：有三种用法，@,.dot(),np.matmul()在实际中最好用的时.dot()因为这个是可以同时进行矩阵，矩阵以及向量之间的运算的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特别注意：对于numpy中的向量在乘法运算的时候是看成1行n列的东西，而我们一般的书写习惯是n行1列，所有在乘法的时候要特别注意运算！！！&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A.dot(B).dot(x.T)=0 # ABx
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;其余的操作&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;A.T #A的转置
np.linalg.inv(A) #A的逆矩阵
np.linalg.det(A) #A的行列式
np.linalg.norm(x, ord=1/2) #对于x的几阶范数
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至少最近做problem set 1就做到这些东西&lt;/p&gt;
&lt;h2&gt;Matplotlib&lt;/h2&gt;
&lt;p&gt;matplotlib感觉全都是套路，直接贴一段显示一个图片的代码一切都明白了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import matplotlib.pyplot as plt
plt.figure()
plt.plot(x_values,y_values,label=&apos;line1) #以(x_value,y_value)中点为线，绘制标签为line1的曲线图
plt.scatter(x_values,y_values,&apos;bo&apos;) #以(x_value,y_value)中点，绘制blue的形状为o的点
plt.xlabel(&apos;x&apos;)
plt.ylabel(&apos;y&apos;)
plt.title(&apos;title&apos;)#这三条语句顾名思义
plt.savefig(path)#将文件存放在电脑的位置
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/background.CDHeIiPc.jpg"/><enclosure url="/_astro/background.CDHeIiPc.jpg"/></item><item><title>CS230 辅助工具：git使用</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-aux-tools-git-usage/cs230-aux-tools-git-usage</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-aux-tools-git-usage/cs230-aux-tools-git-usage</guid><description>CS230 辅助工具：git使用</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今天在更新 &lt;a href=&quot;https://link.zhihu.com/?target=https%3A//wesleyfei1.github.io&quot;&gt;Github-WesleyFei1&lt;/a&gt; 以及CS230的作业仓库的时候，发现自己原本一直使用的GitHub桌面端突然崩掉了，而且桌面端对于版本的控制，同步仓库非常的不方便，于是我学习了一款新的版本控制设备&lt;strong&gt;git&lt;/strong&gt; 的具体使用&lt;/p&gt;
&lt;h2&gt;Git安装&lt;/h2&gt;
&lt;p&gt;首先在google上搜索git的网址，然后点击相应的版本进行下载，进行安装&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;下载.exe文件，安装。要验证git是否安装成功，打开命令行，输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果显示“git version 2.45.0.windows.1”的字样那么就是安装成功&lt;/p&gt;
&lt;h2&gt;Git重要概念&lt;/h2&gt;
&lt;p&gt;git作为最为方便的本地&amp;#x26;云端文件版本控制工具，主要是使用暂存区，Commit区(个人习惯)，远端仓库这几个元素&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;暂存区：用于暂时存储所有决定存入Commit区的东西。（准备提交）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以认为我们本地文件就是一堆的材料，我们的暂存区域就是一个箱子，我们想要将材料放到仓库里面，会选取这些材料中的一部分先放进箱子里面。这里涉及到将箱子中的东西放回去，以及将东西放进箱子两个操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commit区：用于进行本地仓库的版本管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还是使用材料的例子，我们对于暂存区里面的“箱子”会放到Commit区里面，而我们箱子可以放到不同的仓库，仓库之间可以合并等操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;远端仓库：可以与本地的仓库进行互相连接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以认为是外地的大的厂商与本地的小仓库之间的联系。&lt;/p&gt;
&lt;p&gt;从而接下来所有的概念都是对于本地文件夹（想要进行管理的对象）,暂存区，Commit区，远端仓库讨论，一般而言，对于Commit区的“仓库”默认名字叫master(主仓库)，而远端仓库中叫“Origin”在他们下面会有一些的分支，本文称之为dev。而本地的文件夹里面的文件是&lt;strong&gt;与目前的commit区的HEAD指向的文件一致的&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;本地文件夹与暂存区&lt;/h2&gt;
&lt;p&gt;首先我们要设置机器上所使用的远端的GitHub的用户名以及邮箱&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global user.name &quot;....&quot;
git config --global user.email &quot;...@gmail.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入所需要管理的仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd D:
cd wesleyfei.github.io
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用git init将这个目录变成可以用git管理的仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果是这个里面出现了一个.git的东西&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;本地与暂存区域：&lt;/p&gt;
&lt;p&gt;如果我们在本地对于文件** aaa.txt**做出了一些改变，比如我们在里面输入111，想要提交到暂存区里面，则&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git add aaa.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果此时我们将这个命令提交到commit区里，添加注释“添加111到aaa”,那么会有&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果我们在暂存区里面存了一些东西，但是我们不想要要了，可以使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;则可以清空我们的暂存区&lt;/p&gt;
&lt;h2&gt;Commit区与暂存区&lt;/h2&gt;
&lt;p&gt;git的版本管理本质上是一个指针，我们当前的指针指向master下面的哪一个dev，这个dev下面的哪一个“版本”，就可以在这个版本上进行修改。而暂存区向Commit区中提交的命令会提交到相应的版本中。&lt;/p&gt;
&lt;p&gt;我们先考虑不考虑分支dev的情况。&lt;/p&gt;
&lt;p&gt;对于暂存区里面我们存放了一些内容，想要提交到master中，使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git comment -m &quot;一些注释&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一次的git comment命令我们称之为一次操作（操作内容存在该文件下面的.git文件夹里面）&lt;/p&gt;
&lt;p&gt;如果我们需要查看每一次的操作具体修改了那些内容（与当前的版本相比）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git diff .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们想要看过去做过的所有的操作，则&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log# 按q退出
git log --pretty=oneline #简洁表示
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时会显示&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以看到我们现在的HEAD指向的是master的“添加3333到aaa”号版本，我们有的时候想要回退到上一个版本，那么就可以使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git reset --hard HEAD^^ #(对于当前版本指针指向上一次操作，其中^^是由于只有这样才能打出^
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的话就可以进行版本的回退，在执行了这个命令之后，aaa里面的内容就变成了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;111
222
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们想要再次回退到最新的版本（撤销上一次的命令）或者回退到指定位置的任意一个版本，首先我们要查询相应的命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git reflog
# 查看之前若干次的若干次的操作指令
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果会显示之前的每一个操作的一串号码，我们比如说想要回退到“添加111到aaa”，可以使用&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;那么此时我们的HEAD就指向了{0}这一行，而aaa里面的内容自然就变成了111.&lt;/p&gt;
&lt;h2&gt;分支系统&lt;/h2&gt;
&lt;p&gt;分支系统，包括创建分支，如何调整指针的指向以及对于分支到master的合并，这里就体现出来了指针的用处&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 创建分支
git branch dev # 创建了一个名字叫branch的分支
git checkout dev  #将暂存区的指针指向目前的dev区域
git merge dev  #将dev合并到目前HEAD所指向的区域里面
git branch -d dev  #删除dev
# 查看状态
git status
# 由于在合并分支的时候，如果是使用merge的话，删除分支后会丢失分支的信息，因此
git merge -no-ff -m &quot;注释&quot; dev#用这个来合并dev分支
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的命令中，** branch&lt;strong&gt;为创建以及删除分支，&lt;/strong&gt; checkout**命令是对于指针的操作，对于本地的仓库而言，主要就是创建分支，对于分支上进行操作，然后合并到master上面。&lt;/p&gt;
&lt;h3&gt;github拉取与推送&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#将github上仓库里面的东西给拉取到本地
git pull origin master
#将本地的master内的东西提交到github上面
git push origin master
# 克隆github上的东西
git clone https://.....
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般我们都只会用到以上的几种。&lt;/p&gt;
&lt;p&gt;以上都是只有一个人，因为我们都是直接提交到了origin上，如果origin上面有分支dev呢，我们有多人合作任务呢，同时需要对于dev操作，然后提交回origin上面&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 如何将本地的main/dev分支给提交上origin/dev
git push origin dev
# 当多人合作dev时，先将所有的东西给clone下来
git clone https://.../testgit
# 先在本地创建dev
git checkout -b dev origin/dev #从而在HEAD所指向的分支上面也有了这个分支
git push origin dev#此时会被提交到远程的origin/dev下面
# 如果我们需要将远端的dev合并到origin里面，那么就需要将origin-&gt;main然后在本地做合并

# 当我和别人的push冲突了
git pull#然后在本地做合并
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;综上所述，使用git的时候，无论是本地还是云端，好习惯（如果我们要做一个比较大的东西）是** 所有操作在master或origin下的dev里面完成**，对于master，origin实时的更进，而对于dev里面的内容如果经过审核了可以** push到master/origin里面**。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C1:深度神经网络回顾以及代码实现</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c1-dnn-rev/cs230-c1-dnn-rev</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c1-dnn-rev/cs230-c1-dnn-rev</guid><description>CS230 C1:深度神经网络回顾以及代码实现</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;对于cs230主干的第一部分C1而言，coursera的视频课和cs229的神经网络部分重叠度比较高，但是通过programming assignment的实现对于使用python实现NN以及反向传播有了更加深刻的理解。接下来我们来具体的介绍以下&lt;/p&gt;
&lt;h2&gt;深度神经网络的代码实现&lt;/h2&gt;
&lt;p&gt;之前我们在计算参数的导数时，知道使用了链式法则，通过传递一些存储的值节约时间，但是当时在完成作业的时候出现了非常多的问题。为此，我们细致的说说它。&lt;/p&gt;
&lt;h3&gt;代码习惯&lt;/h3&gt;
&lt;p&gt;根据Andrew Ng所说，尽量所有的东西全部用矩阵而不是向量（np.dot(A,B)对于向量计算较麻烦），因此对于一个 x[i]=(x1[i],x2[i],….xn[i])T 以及 X=(x[1],x[2],….x[m]) ,分别用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xi=np.zeros((n,1))# a vector
X=np.zeros((n,m))# input matrix
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数学表达&lt;/h3&gt;
&lt;p&gt;对于第l层的网络而言&lt;/p&gt;
&lt;p&gt;$\begin{aligned} &amp;#x26;\text{Input: } \mathbf{A}^{[l-1]} \ &amp;#x26;\mathbf{Z}^{[l]} = \mathbf{W}^{[l]} \mathbf{A}^{[l-1]} + \mathbf{b}^{[l]} \ &amp;#x26;\mathbf{A}^{[l]} = g^{[l]}(\mathbf{Z}^{[l]}) \ &amp;#x26;\text{Output: } \mathbf{A}^{[l]}, \text{cache}(\mathbf{Z}^{[l]}) \end{aligned}$&lt;/p&gt;
&lt;p&gt;如果我们使用的是规范的表示形式（每个数据&lt;/p&gt;
&lt;p&gt;$x_i$ 是 $n\times 1$ 的矩阵,向量化的输入为 $n\times m$ 那么由链式法则在矩阵求导中推广 $\dfrac{\partial L}{\partial x}=(\dfrac{\partial L}{\partial y}) \cdot \dfrac{\partial y}{\partial x}$ ，在实际的使用时就是对于两个雅可比矩阵的乘积。&lt;/p&gt;
&lt;p&gt;而我们实际使用的时候，有的时候是 $\dfrac{\partial L}{\partial x}=(\dfrac{\partial y}{\partial x})^T \cdot \dfrac{\partial L}{\partial y}$ ，对于这个转置以及顺序该如何确定呢？关键在于维度匹配&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于x如果为  $n\times 1$  ,y为  $m\times 1$&lt;/li&gt;
&lt;li&gt;$\dfrac{\partial y}{\partial x}$  的维度是m*n,由于  $n\times 1=(n\times m)\cdot (m\times 1)$  ,则应该为  $\dfrac{\partial L}{\partial x}=(\dfrac{\partial y}{\partial x})^T \cdot \dfrac{\partial L}{\partial y}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在实际使用时，一般先将每一项的结果求出来，然后进行维度的匹配，根据匹配的结果去得到结果。&lt;/p&gt;
&lt;p&gt;对于&lt;strong&gt;激活函数&lt;/strong&gt; 而言，由于激活函数是对每一个元素作用，因此求导后结果为对应元素点乘。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;向量化表达&lt;/strong&gt; 中，对于参数的梯度，我们是对所有的数据的梯度取平均，然后更新所有的参数。&lt;/p&gt;
&lt;p&gt;$\begin{aligned} &amp;#x26;\text{Input: } d\mathbf{A}^{[l]}, \text{Cache} \ &amp;#x26;d\mathbf{Z}^{[l]} = d\mathbf{A}^{[l]} \odot g&apos;^{[l]}(\mathbf{Z}^{[l]}) \ &amp;#x26;d\mathbf{W}^{[l]} = \frac{1}{m} d\mathbf{Z}^{[l]} \mathbf{A}^{[l-1]\top} \ &amp;#x26;d\mathbf{b}^{[l]} = \frac{1}{m} \sum_{i=1}^{m} d\mathbf{Z}^{[l]} \ &amp;#x26;d\mathbf{A}^{[l-1]} = \mathbf{W}^{[l]\top} d\mathbf{Z}^{[l]} \ &amp;#x26;\text{Output: } d\mathbf{A}^{[l-1]}, d\mathbf{W}^{[l]}, d\mathbf{b}^{[l]} \end{aligned}$&lt;/p&gt;
&lt;p&gt;可以发现，对于每一层的反向传播计算时，会用到上一层对于这层的输出的导数dL/dAl, 因此反向传播的时候会将L对于这层的输入的导数给传播回去&lt;/p&gt;
&lt;p&gt;在使用的时候，由于我们每一层都是由线性层加上激活函数构成的，因此在推导之后直接背下来就可以了。&lt;/p&gt;
&lt;h2&gt;参数传递&lt;/h2&gt;
&lt;p&gt;在进行&lt;strong&gt;前向传播&lt;/strong&gt; 的时候，我们会将所有的&lt;strong&gt;A[l],Z[l],parameters&lt;/strong&gt; 的值存进cache中，方便在反向传播中使用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反向传播&lt;/strong&gt; 的时候会传递&lt;strong&gt;dA[l]&lt;/strong&gt; ，第l层将其作为 $\dfrac{\partial L}{\partial y}$ ,计算对于所有参数的导数，并将 $\dfrac{\partial L}{\partial x}$ 传递回去&lt;/p&gt;
&lt;h2&gt;代码实现&lt;/h2&gt;
&lt;p&gt;对于实现一个任意层数的网络，我们将会编写&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def initialize_parameters_deep(layer_dims):
def linear_forward(A, W, b):
def linear_activation_forward(A_prev, W, b, activation):
def linear_backward(dZ, cache):
def linear_activation_backward(dA, cache, activation):
def compute_cost(AL, Y):
def L_model_forward(X, parameters):
def L_model_backward(AL, Y, caches):
def update_parameters(parameters, grads, learning_rate):
def L_layer_model(X, Y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost=False):
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些函数，用于封装代码。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;初始化函数&lt;/strong&gt; ，如果是为了方便的话对于矩阵参数可以用标准正态分布去初始化，而对于偏置直接置零（其余的初始化方法之后会有所提及）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def initialize_parameters_deep(layer_dims):
    &quot;&quot;&quot;
    parameters -- python dictionary containing your parameters &quot;W1&quot;, &quot;b1&quot;, ..., &quot;WL&quot;, &quot;bL&quot;:
                    Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                    bl -- bias vector of shape (layer_dims[l], 1)
    &quot;&quot;&quot;
    
    np.random.seed(3)
    parameters = {}
    L = len(layer_dims)            # number of layers in the network

    for l in range(1, L):
        
        parameters[&quot;W&quot; + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) * 0.01
        parameters[&quot;b&quot; + str(l)] = np.zeros((layer_dims[l], 1))

    return parameters
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于&lt;strong&gt;前向传播&lt;/strong&gt; ，我们对于每一层而言，需要向前传递，并存储cache。我们将激活函数以及线性层分开实现（方便实现反向传播）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def linear_forward(A, W, b):
    &quot;&quot;&quot;
    Arguments:
    A -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)

    Returns:
    Z -- the input of the activation function, also called pre-activation parameter 
    cache -- a python tuple containing &quot;A&quot;, &quot;W&quot; and &quot;b&quot; ; stored for computing the backward pass efficiently
    &quot;&quot;&quot;
    Z=np.dot(W,A)+b
    
    assert(Z.shape == (W.shape[0], A.shape[1]))
    cache = (A, W, b)
    
    return Z, cache
def linear_activation_forward(A_prev, W, b, activation):
    &quot;&quot;&quot;
    Arguments:
    A_prev -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)
    activation -- the activation to be used in this layer, stored as a text string: &quot;sigmoid&quot; or &quot;relu&quot;

    Returns:
    A -- the output of the activation function, also called the post-activation value 
    cache -- a python tuple containing &quot;linear_cache&quot; and &quot;activation_cache&quot;;
             stored for computing the backward pass efficiently
    &quot;&quot;&quot;
    linear_cache=(A_prev,W,b)
    if activation == &quot;sigmoid&quot;:
        activation_cache,_=sigmoid(np.dot(W,A_prev)+b)
        A=activation_cache
        
    
    elif activation == &quot;relu&quot;:
       activation_cache,_=relu(np.dot(W,A_prev)+b)
        A=activation_cache
    return A, cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;反向传播&lt;/strong&gt; 的实现，我们同样的对于线性层以及激活函数分开实现。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def linear_backward(dZ, cache):
    A_prev, W, b = cache
    m = A_prev.shape[1]

    dA_prev = W.T.dot(dZ)
    dW=1/m * dZ.dot(A_prev.T)
    db=1/m * np.sum(dZ,axis=1,keepdims=True)
    return dA_prev, dW, db
def linear_activation_backward(dA, cache, activation):
    linear_cache, activation_cache = cache
    
    if activation == &quot;relu&quot;:
        dZ=relu_backward(dA,activation_cache)
       
    elif activation == &quot;sigmoid&quot;:
        
        dZ=sigmoid_backward(dA,activation_cache)
       
    dA_prev, dW, db = linear_backward(dZ, linear_cache)
    
    return dA_prev, dW, db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将正向传播串起来,对于1-L遍历并存储cache，并且计算损失函数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def compute_cost(AL, Y):
    &quot;&quot;&quot;
    Returns:
    cost -- cross-entropy cost
    &quot;&quot;&quot;
    m = Y.shape[1]
    cost=-1/m * np.sum(Y*np.log(AL)+(1-Y)*np.log(1-AL))
    cost = np.squeeze(cost)      
    return cost
def L_model_forward(X, parameters):
    &quot;&quot;&quot;
    Returns:
    AL -- last post-activation value
    caches -- list of caches containing:
                every cache of linear_activation_forward() (there are L-1 of them, indexed from 0 to L-1)
    &quot;&quot;&quot;

    caches = []
    A = X
    L = len(parameters) 
    for l in range(1, L):
        A_prev = A 
         A,cache=linear_activation_forward(A_prev,parameters[&quot;W&quot;+str(l)],parameters[&quot;b&quot;+str(l)],activation=&quot;relu&quot;)
        caches.append(cache)
         AL,cache=linear_activation_forward(A,parameters[&quot;W&quot;+str(L)],parameters[&quot;b&quot;+str(L)],activation=&quot;sigmoid&quot;)
    caches.append(cache)
    return AL, caches
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时进行反向传播，单独计算对于最后的输出的导数，作为dAL,然后进行反向传播&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def L_model_backward(AL, Y, caches):
    &quot;&quot;&quot;
    Returns:
    grads -- A dictionary with the gradients
             grads[&quot;dA&quot; + str(l)] = ... 
             grads[&quot;dW&quot; + str(l)] = ...
             grads[&quot;db&quot; + str(l)] = ... 
    &quot;&quot;&quot;
    grads = {}
    L = len(caches) # the number of layers
    m = AL.shape[1]
    Y = Y.reshape(AL.shape) # after this line, Y is the same shape as AL
    
    # Initializing the backpropagation
    
    dAL=(Y/AL+(1-Y)/(1-AL))
    
    current_cache=caches[L-1]
    grads[&quot;dA&quot;+str((L-1))],grads[&quot;dW&quot;+str(L)],grads[&quot;db&quot;+str(L)]=linear_activation_backward(dAL,current_cache,activation=&quot;sigmoid&quot;)
    
    for l in reversed(range(L-1)):
        
        current_cache=caches[l]
        grads[&quot;dA&quot;+str(l)],grads[&quot;dW&quot;+str(l+1)],grads[&quot;db&quot;+str(l+1)]=linear_activation_backward(grads[&quot;dA&quot;+str(l+1)],current_cache,activation=&quot;relu&quot;)
    return grads
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用优化算法（梯度下降）进行参数更新，有&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def update_parameters(parameters, grads, learning_rate):
    L = len(parameters) 
    for l in range(L):
        parameters[&quot;W&quot;+str(l+1)]=parameters[&quot;W&quot;+str(l+1)]-learning_rate*grads[&quot;dW&quot;+str(l+1)]
        parameters[&quot;b&quot;+str(l+1)]=parameters[&quot;b&quot;+str(l+1)]-learning_rate*grads[&quot;db&quot;+str(l+1)]
    return parameters
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从而实现一个训练模型的封装，只要规定好所有的超参数，就可以进行正向传播以及反向传播，并在数据集上进行训练。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def L_layer_model(X, Y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost=False):#lr was 0.009
    
    np.random.seed(1)
    costs = []                         # keep track of cost
    
    # Parameters initialization. parameters=initialize_parameters_deep(layers_dims)
   
    # Loop (gradient descent)
    for i in range(0, num_iterations):

        # Forward propagation: [LINEAR -&gt; RELU]*(L-1) -&gt; LINEAR -&gt; SIGMOID.
        AL,caches=L_model_forward(X,parameters)
       
        # Compute cost.
        cost=compute_cost(AL,Y)
        # Backward propagation.
        grads=L_model_backward(AL,Y,caches)
       
        # Update parameters.
        parameters=update_parameters(parameters,grads,learning_rate)
        
        if print_cost and i % 100 == 0:
            print (&quot;Cost after iteration %i: %f&quot; %(i, cost))
        if print_cost and i % 100 == 0:
            costs.append(cost)
            
    return parameters
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上使用框架实现了一个任意层的网络，之后我们将会对其中的超参数以及优化算法进行讨论。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.D_j6qCmI.jpg"/><enclosure url="/_astro/background.D_j6qCmI.jpg"/></item><item><title>CS230 C2W1&amp;2:模型训练常见trick——正则化方法&amp;梯度调整方法</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c2w1-2-train-tricks-reg-gd/cs230-c2w1-2-train-tricks-reg-gd</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c2w1-2-train-tricks-reg-gd/cs230-c2w1-2-train-tricks-reg-gd</guid><description>CS230 C2W1&amp;2:模型训练常见trick——正则化方法&amp;梯度调整方法</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一章中我们实现了任意大小的神经网络，但是当我们使用非常深的神经网络去进行预测时，会发现在测试集上的表现非常差劲，同时也会对于梯度报一些奇怪的错误。&lt;/p&gt;
&lt;p&gt;这说明我们的深度神经网络非常容易发生&lt;strong&gt;过拟合&lt;/strong&gt; 的问题，并且容易容易发生&lt;strong&gt;梯度爆炸以及梯度消失&lt;/strong&gt; 的问题。针对前者，我们可以使用&lt;strong&gt;正则化，dropout&lt;/strong&gt; 的方法来减小这个问题，而对于后者，我们首先需要进行梯度的检测，对于梯度爆炸以及消失的话我们需要对于&lt;strong&gt;使用一些梯度调整方法&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;正则化方法&lt;/h2&gt;
&lt;p&gt;对于正则化而言，常见的方法是** 参数正则化&lt;strong&gt;以及&lt;/strong&gt; dropout**方法&lt;/p&gt;
&lt;h3&gt;参数正则化&lt;/h3&gt;
&lt;p&gt;参数正则化，就是对于将** 参数的大小也作为惩罚项**，假设原本的损失函数为 $L_{origin}(y, y&apos;)$ ，则 $L_{modified}(y, y&apos;) = L_{origin}(y, y&apos;) + \frac{\lambda}{2} |\theta|_2$ ，如果参数的范数过大，损失函数也会就范数这个方向进行调整。从而减小整体的范数的大小，最后达到减小过拟合趋势这个目的。&lt;/p&gt;
&lt;p&gt;正则化的损失函数实现&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def compute_cost_with_regularization(A3, Y, parameters, lambd):
    &quot;&quot;&quot;
    Arguments:
    A3 -- post-activation, output of forward propagation, of shape (output size, number of examples)
    Y -- &quot;true&quot; labels vector, of shape (output size, number of examples)
    parameters -- python dictionary containing parameters of the model
    
    Returns:
    cost - value of the regularized loss function (formula (2))
    &quot;&quot;&quot;
    m = Y.shape[1]
    W1 = parameters[&quot;W1&quot;]
    W2 = parameters[&quot;W2&quot;]
    W3 = parameters[&quot;W3&quot;]
    
    cross_entropy_cost = compute_cost(A3, Y) 
    cross_entropy_cost+= (lambd/(2*m))*(np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3)))
    return cross_entropy_cost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于参数正则化时，反向传播时对于参数项需要加上 $\lambda\theta$ 这一项&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def backward_propagation_with_regularization(X, Y, cache, lambd):
    &quot;&quot;&quot;
    Implements the backward propagation of our baseline model to which we added an L2 regularization.
    
    Arguments:
    X -- input dataset, of shape (input size, number of examples)
    Y -- &quot;true&quot; labels vector, of shape (output size, number of examples)
    cache -- cache output from forward_propagation()
    lambd -- regularization hyperparameter, scalar
    
    Returns:
    gradients -- A dictionary with the gradients with respect to each parameter, activation and pre-activation variables
    &quot;&quot;&quot;
    m = X.shape[1]
    (Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cache
    
    dZ3 = A3 - Y
    dW3=  1./m *np.dot(dZ3,A2.T)+(lambd/m)*W3
    db3 = 1./m * np.sum(dZ3, axis=1, keepdims = True)
    
    dA2 = np.dot(W3.T, dZ3)
    dZ2 = np.multiply(dA2, np.int64(A2 &gt; 0))
    dW2= 1./m * np.dot(dZ2,A1.T) +(lambd/m) *W2
    db2 = 1./m * np.sum(dZ2, axis=1, keepdims = True)
    
    dA1 = np.dot(W2.T, dZ2)
    dZ1 = np.multiply(dA1, np.int64(A1 &gt; 0))
    dW1=1./m *np.dot(dZ1,X.T) +(lambd/m)*W1
    db1 = 1./m * np.sum(dZ1, axis=1, keepdims = True)
    
    gradients = {&quot;dZ3&quot;: dZ3, &quot;dW3&quot;: dW3, &quot;db3&quot;: db3,&quot;dA2&quot;: dA2,
                 &quot;dZ2&quot;: dZ2, &quot;dW2&quot;: dW2, &quot;db2&quot;: db2, &quot;dA1&quot;: dA1, 
                 &quot;dZ1&quot;: dZ1, &quot;dW1&quot;: dW1, &quot;db1&quot;: db1}
    
    return gradients
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们将其用于一个二分类的系统，&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parameters = model(train_X, train_Y)
print (&quot;On the training set:&quot;)
predictions_train = predict(train_X, train_Y, parameters)
print (&quot;On the test set:&quot;)
predictions_test = predict(test_X, test_Y, parameters)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置超参数 $\lambda=0,0.7$ 则结果为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;lambda=0,0.7&lt;/p&gt;
&lt;p&gt;如果绘制出来分类结果为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;dropout方法&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;what is dropout&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;dropout,故名思意，就是对于每一个iteration内以一定的比例去删除其中的某些连接关系，然后进行正向传播以及反向传播并更新参数，对于每一个iteration都是如此，从而到了最后每一个节点。&lt;/p&gt;
&lt;p&gt;为什么dropout会减少过拟合？因为我们知道神经网络是学习输入的特征的，过拟合表示有的神经元会学到一些噪声数据，然后进行加强了，而dropout则是通过减少这些神经元被迭代的次数，从而减少神经网络学习噪声数据的影响。当然dropout也会有一定的缺点，会导致欠拟合以及重要的信息的丢失，所以使用频率不如正则化参数。&lt;/p&gt;
&lt;p&gt;** how to conduct dropout?**&lt;/p&gt;
&lt;p&gt;我们会对于每一次iteration执行之前，添加一个mask层，对于这个mask层是一个对应元素连接的，全部参数为True或False的层。如果为True，则会继续传递，反之会传递参数0。用图形表示即为&lt;/p&gt;
&lt;p&gt;同时由于我们设置每一个点dropout的概率为keep_prob,为了保证整体的均值不变，对于每一层生成的数据要** 除keep_prob**来保证均值不变。&lt;/p&gt;
&lt;p&gt;因此对于每一个iteration中，我们会** 随机生成每一层的mask**, 然后将mask层添加到正向传播以及反向传播中。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def forward_propagation_with_dropout(X, parameters, keep_prob = 0.5):
    np.random.seed(1)
    
    # retrieve parameters
    W1 = parameters[&quot;W1&quot;]
    b1 = parameters[&quot;b1&quot;]
    W2 = parameters[&quot;W2&quot;]
    b2 = parameters[&quot;b2&quot;]
    W3 = parameters[&quot;W3&quot;]
    b3 = parameters[&quot;b3&quot;]
    
    # LINEAR -&gt; RELU -&gt; LINEAR -&gt; RELU -&gt; LINEAR -&gt; SIGMOID
    Z1 = np.dot(W1, X) + b1
    A1 = relu(Z1)
    # add mask
    D1=np.random.rand(A1.shape[0],A1.shape[1])
    D1=(D1&amp;#x3C;keep_prob).astype(int)
    # apply mask
    A1=A1*D1
    A1=A1/(keep_prob)
    
    Z2 = np.dot(W2, A1) + b2
    A2 = relu(Z2)
    D2 = np.random.rand(A2.shape[0],A2.shape[1])
    D2 = (D2 &amp;#x3C; keep_prob).astype(int)
    A2 = A2 * D2
    A2 = A2 / keep_prob
    
    Z3 = np.dot(W3, A2) + b3
    A3 = sigmoid(Z3)
    
    cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3)
    
    return A3, cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而反向传播同理，也要注意均值的处理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def backward_propagation_with_dropout(X, Y, cache, keep_prob):
    
    
    m = X.shape[1]
    (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cache
    
    dZ3 = A3 - Y
    dW3 = 1./m * np.dot(dZ3, A2.T)
    db3 = 1./m * np.sum(dZ3, axis=1, keepdims = True)
    dA2 = np.dot(W3.T, dZ3)
    ### START CODE HERE ### (≈ 2 lines of code)
    dA2=dA2*D2
    dA2=dA2/(keep_prob)
    ### END CODE HERE ###
    dZ2 = np.multiply(dA2, np.int64(A2 &gt; 0))
    dW2 = 1./m * np.dot(dZ2, A1.T)
    db2 = 1./m * np.sum(dZ2, axis=1, keepdims = True)
    
    dA1 = np.dot(W2.T, dZ2)
    dA1=dA1*D1
    dA1=dA1/(keep_prob)
    
    dZ1 = np.multiply(dA1, np.int64(A1 &gt; 0))
    dW1 = 1./m * np.dot(dZ1, X.T)
    db1 = 1./m * np.sum(dZ1, axis=1, keepdims = True)
    
    gradients = {&quot;dZ3&quot;: dZ3, &quot;dW3&quot;: dW3, &quot;db3&quot;: db3,&quot;dA2&quot;: dA2,
                 &quot;dZ2&quot;: dZ2, &quot;dW2&quot;: dW2, &quot;db2&quot;: db2, &quot;dA1&quot;: dA1, 
                 &quot;dZ1&quot;: dZ1, &quot;dW1&quot;: dW1, &quot;db1&quot;: db1}
    
    return gradients
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后我们的结果为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以发现，对于添加正则项以及dropout确实可以减少过拟合的趋势&lt;/p&gt;
&lt;h3&gt;其余常见的正则化方法：&lt;/h3&gt;
&lt;p&gt;实际使用的时候还有一些常见的方法。&lt;/p&gt;
&lt;p&gt;其一是&lt;strong&gt;early ending&lt;/strong&gt;,就是等到训练到中途，这个时候模型在测试数据集上的表现最好的时候提前结束&lt;/p&gt;
&lt;p&gt;其二是** 增加数据量**，尤其是在CV中，可以对于一张图片，选取其中几个小部分作为新的数据，也可以做旋转，翻转，颜色上做一些处理，反正就就是** 想尽办法增加数据量**&lt;/p&gt;
&lt;p&gt;其三是** 模型融合**，这个在cs229的笔记中有详细的介绍&lt;/p&gt;
&lt;h2&gt;梯度调整方法&lt;/h2&gt;
&lt;p&gt;在训练的时候由于在传播的途径中会有大量的东西进行相乘，这可能会导致当传播到深层次的网络时，梯度爆炸/消失。为了避免这个问题，我们会采取几种策略来应对它。&lt;/p&gt;
&lt;h3&gt;梯度检测方法&lt;/h3&gt;
&lt;p&gt;梯度检测方法可以有效的检验我们训练出的模型有没有发生梯度消失/爆炸的方法。它是通过定义计算梯度来验证反向传播中梯度计算是否有问题。&lt;/p&gt;
&lt;p&gt;具体方法：假设我们要考察 $\theta$ 的梯度&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 $grad_{true}=\dfrac{\partial J}{\partial \theta} = \lim_{\varepsilon \to 0} \dfrac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon} \tag{1}$&lt;br&gt;
，即为设参数 $\theta:=\theta+\epsilon,-\epsilon$ 并进行正向传播，计算最后的损失函数，这样计算得到的梯度是精确的&lt;/li&gt;
&lt;li&gt;使用反向传播计算出 $grad=\dfrac{\partial J}{\partial \theta}$&lt;/li&gt;
&lt;li&gt;计算整体差值于整体的比例 $ difference = \dfrac {\mid\mid grad - gradapprox \mid\mid_2}{\mid\mid grad \mid\mid_2 + \mid\mid gradapprox \mid\mid_2} \tag{2}$&lt;/li&gt;
&lt;li&gt;若difference&gt;k，那么可以认为整体式梯度出现了问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体代码实现&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def gradient_check_n(parameters, gradients, X, Y, epsilon = 1e-7):
    # Set-up variables
    parameters_values, _ = dictionary_to_vector(parameters)
    grad = gradients_to_vector(gradients)
    num_parameters = parameters_values.shape[0]
    J_plus = np.zeros((num_parameters, 1))
    J_minus = np.zeros((num_parameters, 1))
    gradapprox = np.zeros((num_parameters, 1))
    
    # Compute gradapprox
    for i in range(num_parameters):
        
        # Compute J_plus[i]. Inputs: &quot;parameters_values, epsilon&quot;. Output = &quot;J_plus[i]&quot;.
        # &quot;_&quot; is used because the function you have to outputs two parameters but we only care about the first one
        parameters_value=np.copy(parameters_values)
        parameters_value[i]+=epsilon
        J_plus[i],_=forward_propagation_n(X,Y,vector_to_dictionary(parameters_value))
        # Compute J_minus[i]. Inputs: &quot;parameters_values, epsilon&quot;. Output = &quot;J_minus[i]&quot;.
        parameters_value=np.copy(parameters_values)
        parameters_value[i]-=epsilon
        J_minus[i],_=forward_propagation_n(X,Y,vector_to_dictionary(parameters_value))
        
        # Compute gradapprox[i]
        gradapprox[i]=(J_plus[i]-J_minus[i])/(2*epsilon)
    
    # Compare gradapprox to backward propagation gradients by computing difference.
    print(grad)
    difference=(np.linalg.norm(gradapprox-grad,ord=2))/(np.linalg.norm(gradapprox,ord=2)+np.linalg.norm(grad,ord=2))
    if difference &gt; 2e-7:
        print (&quot;\033[93m&quot; + &quot;There is a mistake in the backward propagation! difference = &quot; + str(difference) + &quot;\033[0m&quot;)
    else:
        print (&quot;\033[92m&quot; + &quot;Your backward propagation works perfectly fine! difference = &quot; + str(difference) + &quot;\033[0m&quot;)
    return difference
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;gradient checking可以有效的检验梯度是否有问题，但是我们由于每一次check&lt;strong&gt;时间复杂度非常高&lt;/strong&gt; ，因此不会每一次都去计算。实际应用的时候可以没隔开几次检查一下。&lt;/p&gt;
&lt;h3&gt;初始化方法&lt;/h3&gt;
&lt;p&gt;初始化是解决梯度爆炸的一种方法，初始化的不同位置可以调整我们每一次对梯度修改的幅度，从而避免一大堆的&gt;1的数字乘在一起，导致梯度爆炸。&lt;/p&gt;
&lt;p&gt;于此同时，由于我们希望不同的神经元可以学习到不同的特征以及信息，而不是全部学习某一种特征，因此我们需要添加一些随机性，使得不同方向的特征都可以被学习到。&lt;/p&gt;
&lt;p&gt;需要初始化的参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;weight&lt;/strong&gt; matrices  $(W^{[1]}, W^{[2]}, W^{[3]}, ..., W^{[L-1]}, W^{[L]})$&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;bias&lt;/strong&gt; vectors  $(b^{[1]}, b^{[2]}, b^{[3]}, ..., b^{[L-1]}, b^{[L]})$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于bias而言，我们是一般是初始化为0，避免发生避免发生偏置现象。即为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parameters[&apos;b&apos;+str(l)]=np.zeros((layers_dims[l],1))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于ReLU函数是最为常见的损失函数，它会过滤调负数的数据，因此结合我们一般都是使用正态分布来初始化，因此我们只要对于Weight设置合理的方差即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parameters[&apos;W&apos;+str(l)]=np.random.randn((layers_dims[l],layers_dims[l-1]))*sigma
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只要设计 $\sigma$ 的值就可以&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;错误的案例：0初始化  $\sigma=0$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标准正态分布&lt;/strong&gt;  $\sigma=1$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;He 初始化&lt;/strong&gt; ：我们希望 $z=Wx+b$ 中z的方差不要跟着层数的增长而增长，由概率论知 $Var(z)=n_{in}\cdot Var(w) \cdot Var(x)$ 有 $Var(W)=\dfrac{1}{n_{in}}$ 。考虑到反向传播的因素，有 $Var(W)=\dfrac{2}{n_{in}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从而有 $W \sim \mathcal{N}\left(0, \sqrt{\frac{2}{n_{\text{in}}}}\right)$ ,即为He initialization，He初始化对于&lt;strong&gt;ReLU&lt;/strong&gt; 函数的网络效果特别好&lt;/p&gt;
&lt;p&gt;分别使用以上几种方法初始化的分类结果为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;zeros, randn, He initialization&lt;/p&gt;
&lt;h3&gt;批量归一化（batch normalization）&lt;/h3&gt;
&lt;p&gt;通过初始化来减小梯度爆炸/消失是一种手段，但是我们还可以通过直接规定某一层的输入的均值以及方差来进行初始化。&lt;/p&gt;
&lt;p&gt;批量归一化，是建立在批量(输入X中的m的大小)输入的基础上进行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;训练的时候&lt;/strong&gt; 步骤为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;归一化：对于某一层 $z=Wx+b$ 之前， $x=(x^1 ,x^2 ,....... x^m)$ 先计算个batch的输入的均值以及方差&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$\mu_B = \frac{1}{m} \sum_{i=1}^{m} x_i, \quad\sigma_B^2 = \frac{1}{m} \sum_{i=1}^{m} (x_i - \mu_B)^2$ ,然后归一化 $\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}$ 。通过这个步骤使得输入x均值为0，方差为1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;建立可学习参数：对于传输到这一层真正的参数x，需要建立可以学习的东西，考虑可学习参数 $\gamma,\beta \in R^{m\times 1}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$x_{in}=\gamma\odot\hat{x}+\beta$ ,将这个 $x_in$ 作为下一层的输入。&lt;/p&gt;
&lt;p&gt;而对于&lt;strong&gt;预测&lt;/strong&gt; 的时候，对于每一层的 $\mu_B,\sigma_B$ 我们直接使用训练的时候得到的数据进行预测。可以发现，我们对于b参数直接平移到了 $\beta$ 参数上了。&lt;/p&gt;
&lt;p&gt;batch normalization可以有效控制整体的梯度在1左右的范围，同时可以提升整体的鲁棒性，但是缺点是batch要求比较大，需要更大的批次来提升归一化的性能。&lt;strong&gt;批量归一化是对于深度神经网络非常重要的一种方法。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以上我们介绍了在进行模型训练的时候对于过拟合以及欠拟合常见的两个trick，但是这些都只能算是trick，真正重要的还是我们的超参数的设置。而为了学习更深的神经网络，就需要使用一些特殊的优化方法，这些将会在接下来的文章中讨论&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C2W3：优化算法探究</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c2w3-opt-alg/cs230-c2w3-opt-alg</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c2w3-opt-alg/cs230-c2w3-opt-alg</guid><description>CS230 C2W3：优化算法探究</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;为了学习更深的神经网络，我们需要更多的数据以及更深的神经网络，而把训练数据一次性输入大&lt;strong&gt;量占用内存&lt;/strong&gt; ，显然不是特别好的解决方案。因此我们接下来将会介绍&lt;strong&gt;mini-batch training&lt;/strong&gt;,同时我们会介绍如何** 更加快速的训练**，即选择更加高效的优化算法。&lt;/p&gt;
&lt;h2&gt;mini-batch training&lt;/h2&gt;
&lt;p&gt;之前我们的输入是 $X=(x^1,x^2,...x^n)$ （batch training）每一个iteration将所有的东西输入进去，而于此同时我们也可以一个一个的输入，即为每一个iteration只输入一个 $x^i$ (stochastic gradient descent随机梯度下降)。&lt;/p&gt;
&lt;p&gt;对于前者，一方面如果n非常的大，在每一次正向传播以及反向传播所需要的时间就非常的长，** 时间成本过大**。对于后者，由于单个数据之间的方差过大，会导致参数一直在最低点附近徘徊，** 总体效果非常差**。&lt;/p&gt;
&lt;p&gt;因此我们使用一种介于中间的方法：** Mini-batch training**&lt;/p&gt;
&lt;p&gt;我们不会将所有的训练数据一股脑输入，而是分割成batch=256/128/…的块。&lt;/p&gt;
&lt;p&gt;数学上即有 $X=(X^1,X^2,.....X^{n-1},X^n)$ ,其中 $X^i=[x^{(i-1)*batch+1},x^{(i-1)*batch+2},x^{(i-1)*batch+3}....x^{(i-1)*batch+batch}]$&lt;/p&gt;
&lt;p&gt;(对于最后一个batch取余数,在分割数据集之前先将所有的数据打乱)，这样划分之后每一个 $X^i$ 称为一个mini-batch&lt;/p&gt;
&lt;p&gt;在每一个iteration中我们输入一个mini-batch,将整体循环几个epoch，得到最终的结果&lt;/p&gt;
&lt;p&gt;mini-batch相比于batch training中，iteration之间不一定会使得Loss下降，但是由于mini-batch的作用，他在整体方差上会比随机梯度下降小的多，在执行了更多个iteration之后，仍然会收敛到最后的结果。&lt;/p&gt;
&lt;p&gt;从Contour图上看，收敛的情况&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;而在loss曲线上，则是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;因此，mini-batch training会在除了&lt;strong&gt;batch normalization&lt;/strong&gt; 中的性能有所影响，一般而言，Loss曲线都会以一个振荡的形式沿着batch training的曲线下降。今后的训练我们一般都会使用mini-batch training&lt;/p&gt;
&lt;p&gt;于此同时，对于mini-batch training中的batch的值一般取&lt;strong&gt;2的指数幂&lt;/strong&gt; ，64，128，256之类的。&lt;/p&gt;
&lt;h2&gt;优化方法&lt;/h2&gt;
&lt;p&gt;之前我们更新参数都是使用&lt;strong&gt;梯度下降&lt;/strong&gt; （沿着当前梯度最大的方向下降），相当于在参数空间上沿着山脊下降到山谷，但是如果想如图的画面时，就会画相对较长的时间。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;从contour图的角度去看，就是在某些方向上我们的loss曲线振荡较为厉害，但是却没有向山谷前进更多的距离&lt;/p&gt;
&lt;p&gt;如图中，我们希望在y轴方向上&lt;strong&gt;减小变化的速率&lt;/strong&gt; （让数据变化更加平稳，避免梯度爆炸），同时我们希望可以加快在&lt;strong&gt;x轴上移动的速率&lt;/strong&gt; （加快收敛的速率），针对这两者我们分别使用&lt;strong&gt;Momentum以及RMSprop&lt;/strong&gt; 来解决，最后结合这两种优化方法的优点可以研究出&lt;strong&gt;Adam&lt;/strong&gt; 优化方法。&lt;/p&gt;
&lt;h3&gt;Momentum(动量法)&lt;/h3&gt;
&lt;p&gt;动量在Physics中是指物体可以保持原有的物体的运动属性的衡量标准，而我们想要通过动量加快在x轴收敛速度，可以使用Momentum(动量法)&lt;/p&gt;
&lt;p&gt;$\theta=\theta-\alpha\dfrac{\partial J}{\partial \theta}$ 为我们的梯度下降，对于此时的每一次的参数变化速率 $\dfrac{\partial J}{\partial \theta}$ 并没有考虑到过去的情况。&lt;/p&gt;
&lt;p&gt;为了保持原有的运动属性，我们将之前的变化趋势也要考虑进去，具体为&lt;/p&gt;
&lt;p&gt;$v_{d\theta}=\gamma\times v_{d\theta}+(1-\gamma)\dfrac{\partial J}{\partial \theta}$&lt;/p&gt;
&lt;p&gt;$\theta=\theta-learning_rate\cdot v_{d\theta}$&lt;/p&gt;
&lt;p&gt;我们将 $\dfrac{\partial J}{\partial \theta}$ 看成了Loss曲线的下降的加速度，加入了 $v_{d\theta}$ 来记录物体的速度，从而可以保持过往的变化趋势，进而考虑考虑到加速度里面，加快收敛速率&lt;/p&gt;
&lt;p&gt;从contour图上来看就是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;代码实现如下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def update_parameters_with_momentum(parameters, grads, v, beta, learning_rate):
    # in this function, we use gamma as the rate of change of the velocity

    L = len(parameters) // 2 # number of layers in the neural networks
    
    # Momentum update for each parameter
    for l in range(L):
        # update the velocity
        v[&apos;dW&apos;+str(l+1)]=beta*v[&apos;dW&apos;+str(l+1)]+(1-beta)*grads[&apos;dW&apos;+str(l+1)]
        v[&apos;db&apos;+str(l+1)]=beta*v[&apos;db&apos;+str(l+1)]+(1-beta)*grads[&apos;db&apos;+str(l+1)]
        # update the &apos;x&apos; in the space
        parameters[&apos;W&apos;+str(l+1)]-=learning_rate*v[&apos;dW&apos;+str(l+1)]
        parameters[&apos;b&apos;+str(l+1)]-=learning_rate*v[&apos;db&apos;+str(l+1)]
        
    return parameters, v
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;RMSprop&lt;/h3&gt;
&lt;p&gt;Momentum是使用动量来减少在y轴上的变化速率，而RMSprop则是通过计算通过惩罚的机制来惩罚那些变化过快的地方，奖赏那些变化比较快的地方，惩罚振荡过大的地方（RMSprop主要是针对y轴）&lt;/p&gt;
&lt;p&gt;RMSprop的数学表达式&lt;/p&gt;
&lt;p&gt;$s_t = \beta \cdot s_{t-1} + (1 - \beta) \cdot d\theta^2 \  \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{s_t} + \epsilon} \cdot d\theta$&lt;/p&gt;
&lt;p&gt;其中 $s$ 为记录了过往的总的运动的路程的范数，从而在更新的时候，如果我们在y轴上振荡过快，就会有总的路程较大，我们也会做出较大的惩罚。对于x轴上，最一开始如果变化教慢， $d\theta^2$ 使得v比较小，进而加快 $\theta$ 在x轴上的变化速率&lt;/p&gt;
&lt;p&gt;为了避免在更新的时候&lt;strong&gt;分母上有0&lt;/strong&gt; 的出现，我们会加上一个 $\epsilon=1e-8$ 来避免inf的出现&lt;/p&gt;
&lt;p&gt;图形化表示就是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Adam&lt;/h3&gt;
&lt;p&gt;Momentum，RMSprop一个加速，一个减速，我们同时考虑记录总的路程以及速度，而我们对于过往状态的考虑也不需要考虑过长时间的状态，需要添加一个&lt;strong&gt;收敛项&lt;/strong&gt; （有点类似于cs229中的Locally Weight Linear Model)最后得到Adam的更新公式&lt;/p&gt;
&lt;p&gt;$\begin{aligned} v_{dW^{[l]}} &amp;#x26;= \beta_1 v_{dW^{[l]}} + (1 - \beta_1) \frac{\partial \mathcal{J}}{\partial W^{[l]}} \ v_{dW^{[l]}}^{\text{corrected}} &amp;#x26;= \frac{v_{dW^{[l]}}}{1 - (\beta_1)^t} \ s_{dW^{[l]}} &amp;#x26;= \beta_2 s_{dW^{[l]}} + (1 - \beta_2) \left( \frac{\partial \mathcal{J}}{\partial W^{[l]}} \right)^2 \ s_{dW^{[l]}}^{\text{corrected}} &amp;#x26;= \frac{s_{dW^{[l]}}}{1 - (\beta_2)^t} \ W^{[l]} &amp;#x26;= W^{[l]} - \alpha \frac{v_{dW^{[l]}}^{\text{corrected}}}{\sqrt{s_{dW^{[l]}}^{\text{corrected}} + \varepsilon}} \end{aligned}$&lt;/p&gt;
&lt;p&gt;其中W为参数，对于速度以及路程，在运行之前先全部归0。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.01,
                                beta1 = 0.9, beta2 = 0.999,  epsilon = 1e-8):
    
    L = len(parameters) // 2                 # number of layers in the neural networks
    v_corrected = {}                         # Initializing first moment estimate, python dictionary
    s_corrected = {}                         # Initializing second moment estimate, python dictionary
    
    # Perform Adam update on all parameters
    for l in range(L):
        # Moving average of the gradients. Inputs: &quot;v, grads, beta1&quot;. Output: &quot;v&quot;.
        v[&apos;dW&apos;+str(l+1)]=beta1*v[&apos;dW&apos;+str(l+1)]+(1-beta1)*(grads[&apos;dW&apos;+str(l+1)])
        v[&apos;db&apos;+str(l+1)]=beta1*v[&apos;db&apos;+str(l+1)]+(1-beta1)*(grads[&apos;db&apos;+str(l+1)])

        # Compute bias-corrected first moment estimate. Inputs: &quot;v, beta1, t&quot;. Output: &quot;v_corrected&quot;.
        v_corrected[&apos;dW&apos;+str(l+1)]=v[&apos;dW&apos;+str(l+1)]/(1-np.power(beta1,t))
        v_corrected[&apos;db&apos;+str(l+1)]=v[&apos;db&apos;+str(l+1)]/(1-np.power(beta1,t))

        # Moving average of the squared gradients. Inputs: &quot;s, grads, beta2&quot;. Output: &quot;s&quot;.
        s[&apos;dW&apos;+str(l+1)]=beta2*s[&apos;dW&apos;+str(l+1)]+(1-beta2)*(np.power(grads[&apos;dW&apos;+str(l+1)],2))
        s[&apos;db&apos;+str(l+1)]=beta2*s[&apos;db&apos;+str(l+1)]+(1-beta2)*(np.power(grads[&apos;db&apos;+str(l+1)],2))

        # Compute bias-corrected second raw moment estimate. Inputs: &quot;s, beta2, t&quot;. Output: &quot;s_corrected&quot;.
        s_corrected[&apos;dW&apos;+str(l+1)]=s[&apos;dW&apos;+str(l+1)]/(1-np.power(beta2,t))
        s_corrected[&apos;db&apos;+str(l+1)]=s[&apos;db&apos;+str(l+1)]/(1-np.power(beta2,t))
        # Update parameters. Inputs: &quot;parameters, learning_rate, v_corrected, s_corrected, epsilon&quot;. Output: &quot;parameters&quot;.
        parameters[&apos;W&apos;+str(l+1)]-=learning_rate*v_corrected[&apos;dW&apos;+str(l+1)]/(np.sqrt(s_corrected[&apos;dW&apos;+str(l+1)])+epsilon)
        parameters[&apos;b&apos;+str(l+1)]-=learning_rate*v_corrected[&apos;db&apos;+str(l+1)]/(np.sqrt(s_corrected[&apos;db&apos;+str(l+1)])+epsilon)
    return parameters, v, s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时对于一个二分类问题使用以上的过去的Gradient Descent以及Adam Optimizer,Loss以及结果如图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;gradient descent&amp;#x26; adam&lt;/p&gt;
&lt;p&gt;综上所述，Mini-Batch training以及Adam 优化方法在实际的使用中是非常常用的，不仅可以大大的加快我们训练的iteration数量，同时也可以加快我们收敛的速率以及准确率。我们在自己进行模型训练的时候，可以考虑使用这两者。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C3W1:卷积神经网络简介</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c3w1-cnn-intro/cs230-c3w1-cnn-intro</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c3w1-cnn-intro/cs230-c3w1-cnn-intro</guid><description>CS230 C3W1:卷积神经网络简介</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;之前我们对于层与层的连接中基本都是用&lt;strong&gt;全连接层&lt;/strong&gt; ，但这样对于一张正常的图片至少为  $64\times64\times3=12288$  个参数，对于第一层的全连接层就至少有1M的参数，因此我们基于图片本身的特点，设计出一种新的网络结构——&lt;strong&gt;CNN&lt;/strong&gt; (Convolutional Neural Network).&lt;/p&gt;
&lt;h2&gt;卷积核假设&amp;#x26;卷积操作：&lt;/h2&gt;
&lt;p&gt;对于一般的图片，我们假设：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图像的局部区域是&lt;strong&gt;高度相关的&lt;/strong&gt; ，即为任何一个区域内部的点之间都会有所关联（需要&lt;strong&gt;Fully Connect&lt;/strong&gt; ）&lt;/li&gt;
&lt;li&gt;任何一个点所要表达的信息与距离其较远的点所传达的信息&lt;strong&gt;无直接关联&lt;/strong&gt; 。即为对于Fully Connect只需要考虑一个局部特征。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此我们需要一种操作，只会对于图像上每一个小的局部区域内进行全连接操作，即为&lt;strong&gt;卷积操作&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于卷积操作&lt;/p&gt;
&lt;p&gt;首先是定义一个** 卷积核**：n*n的卷积核  $K_{ij},i,j\in[1,r]$  ,如果我们要对于一张2D的图片进行操作，假设图片为  $A_{kl}$  长宽分别为m和n,那么对于结果  $B$  为一个  $(m-r+1)*(n-r+1)$  的矩阵，其中每一个元素为&lt;/p&gt;
&lt;p&gt;$B_{i,j}=\Sigma^{k-1}&lt;em&gt;{x=0}\Sigma^{k-1}&lt;/em&gt;{y=0} A_{i+x,j+y}K_{x,y}$  相当于对于&lt;strong&gt;r*r内的东西做了一个全连接层&lt;/strong&gt;，只是形状有点特殊。&lt;/p&gt;
&lt;p&gt;具体而言就是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;卷积介绍&lt;/p&gt;
&lt;p&gt;用numpy表示就是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;b[i,j]=np.sum(A[i:i+m-r,j:j+m-r]*K[:,:])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有了卷积操作，我们就可以来构建我们的CNN的各个部分了,首先来输入只有2维。&lt;/p&gt;
&lt;h2&gt;卷积神经网络&lt;/h2&gt;
&lt;h3&gt;Layer Type1:卷积层&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;输入&lt;/strong&gt; ：一个m&lt;em&gt;n的图片 &lt;strong&gt;参数&lt;/strong&gt; ：一个大小为r *&lt;/em&gt; r的卷积核，间隔的步数stride, 边缘填充格数padding&lt;/p&gt;
&lt;p&gt;我们发现如果我们直接进行卷积操作，那么会导致边缘上的数据被卷到的次数较少，因此我们考虑在边缘上添加一些空格，减少** 数据的丢失**。具体操作是：在m*n的图片的上下左右各添加p行（列）空行（列），则此时图片大小为  $(m+2p)*(n+2p)$  ,这一步称为&lt;strong&gt;填充(padding)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;然后我们对于padding之后的图片进行卷积操作，但是对于  $b_{00}=A[0:r,0:r]*K$  操作之后，对于  $b_{01}=A[0:r,1:r+1]*K$  可以x方向跳过s步（称为&lt;strong&gt;stride&lt;/strong&gt; ），然后再将卷积后的结果作为b01，即为&lt;/p&gt;
&lt;p&gt;$b_{01}=A[0:r,s:r+s]*K$&lt;/p&gt;
&lt;p&gt;因此具体表达式就是进行padding之后  $B_{i,j}=\Sigma^{k-1}&lt;em&gt;{x=0}\Sigma^{k-1}&lt;/em&gt;{y=0} A_{i&lt;em&gt;s+x,j&lt;/em&gt;s+y}K_{x,y}$  ，经过操作之后输出的大小为 $[\dfrac{m+2p-r}{s}+1]\times[\dfrac{n+2p-r}{s}+1]$&lt;/p&gt;
&lt;p&gt;图像化表示就是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;卷积层+padding+stride图形化表示&lt;/p&gt;
&lt;p&gt;相应的，每一个卷积层实际上就是一个“全连接层”,因此我们会添加上一个激活函数。&lt;/p&gt;
&lt;h3&gt;Layer Type2:池化层&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;输入&lt;/strong&gt; ：一个m*n的图片  &lt;strong&gt;参数&lt;/strong&gt; ：池化的大小  $r$  , 池化的类型，函数  $f=max/mean/...$&lt;/p&gt;
&lt;p&gt;对于池化操作，与卷积操作类似，卷积为点对应相乘然后相加，而对于池化为对于  $r*r$  区域内部用f作用，如取平均值（mean)或者是取最大值（max),即为&lt;/p&gt;
&lt;p&gt;$B_{i,j}=f_{0&amp;#x3C;x&amp;#x3C;r-1\0&amp;#x3C;y&amp;#x3C;r-1}( A_{i+x,j+y}K_{x,y})$  ,其中f为max或mean&lt;/p&gt;
&lt;p&gt;同样的也有填充与间隔（stride,padding）&lt;/p&gt;
&lt;p&gt;在池化之后得到结果为  $[\dfrac{m+2p-r}{s}+1]\times[\dfrac{n+2p-r}{s}+1]$&lt;/p&gt;
&lt;h3&gt;Layer Type3:归一化层&lt;/h3&gt;
&lt;p&gt;归一化层（Batch Norm层），故名思意，就是对于经过每一个2D的卷积核卷出来的2D图像中的东西进行归一化，这样可以有效的表面梯度爆炸等，从而可以增加我们的训练的层数。&lt;/p&gt;
&lt;h3&gt;三维操作——通道（channel)&lt;/h3&gt;
&lt;p&gt;以上我们都默认卷积核，池化（核）以及输入为二维的，实际中，我们的输入常常为RGB三色的输入  $64\times64\times3$  ，而我们想要得到的结果是&lt;strong&gt;若干个可以表示图片在不同方面的特征&lt;/strong&gt; 的2D“图片”，下面我们将其拓展到三维。&lt;/p&gt;
&lt;p&gt;假设我们的输入为  $m&lt;em&gt;n&lt;/em&gt;c$  ，接下来只以卷积举例，池化同理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;理解方式1&lt;/strong&gt; ：可以将其看成c张  $m&lt;em&gt;n$  &lt;em&gt;的图片，我们使用c个&lt;/em&gt;  $r&lt;/em&gt;r$  的卷积核，分别对于每一个图片层进行卷积操作，得到c张大小为  $m&apos;*n&apos;$  的图片层，我们考虑将每一个图片层对应位置的数加起来（将c个图片层拍成一个图片层），最后得到一个  $m&apos;*n&apos;$  的图片&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;理解方式2&lt;/strong&gt; : 我们就直接对于  $m&lt;em&gt;n&lt;/em&gt;c$  的图片，将卷积核看成是  $r&lt;em&gt;r&lt;/em&gt;c$  ,对于卷积的对象，之前是一个  $r&lt;em&gt;r$  的区域，现在我们是  $r&lt;/em&gt;r*c$  的一个体，具体为&lt;/p&gt;
&lt;p&gt;$B_{i,j}=\Sigma^{c}&lt;em&gt;{o=1}\Sigma^{k-1}&lt;/em&gt;{x=0}\Sigma^{k-1}&lt;em&gt;{y=0} A&lt;/em&gt;{i+x,j+y,o}K_{x,y,o}$  ,  $i,j\in m&apos;*n&apos;$  而在操作之后的2D图片大小计算和原来一样。&lt;/p&gt;
&lt;p&gt;由此我们只能得到一个2D图片，表示在ij位置东西在该方面的特征，而如果我们想要提取结果在&lt;strong&gt;多方面的特征&lt;/strong&gt; ，就需要使用  $c&apos;$  个卷积核，最后得到  $c&apos;$  个大小为  $m&apos;*n&apos;$  的图片，输出为  $m&apos;*n&apos;*c&apos;$  的东西，图形表示为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;卷积+channels&lt;/p&gt;
&lt;p&gt;因此我们将channel=3的图片输入，然后不断通过卷积层/池化层，最后直到一个比较小的图片  $4&lt;em&gt;4&lt;/em&gt;channels$  ,此时的channels就会提取到图片的较深层次的信息，此时我们直接将其拍成一个一维的向量，然后再通过若干的全连接层，最后得到我们的答案。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;CNN&lt;/p&gt;
&lt;p&gt;以上我们介绍了基本的卷积神经网络的组成部件，包括卷积层，全连接层，池化层以及通道的概念，除了通道有点难以理解以外，CNN整体上还是非常漂亮的。在之后的文章中我们将会由此介绍若干经典的神经网络（LeNet5,AlexNet,VGG16,ResNet...），以及用于物体识别（YOLO)以及人脸识别算法。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C4W2: 经典卷积神经网络设计及CNN常见应用</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c4w2-classic-cnn-designs-apps/cs230-c4w2-classic-cnn-designs-apps</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c4w2-classic-cnn-designs-apps/cs230-c4w2-classic-cnn-designs-apps</guid><description>CS230 C4W2: 经典卷积神经网络设计及CNN常见应用</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS230 C4W2-5: 经典卷积神经网络设计及CNN常见应用&lt;/p&gt;
&lt;p&gt;之前我们探讨了什么是CNN，CNN的基本架构，但是&lt;strong&gt;设计CNN&lt;/strong&gt; 取得最好的效果也非常重要。经典的CNN设计可以给我们提供这种设计的思路，而当我们知道如何设计一个CNN之后，在落实到具体的项目（人脸识别，图像生成，物体识别）时又分别有些独特的地方，下面将会一一进行介绍&lt;/p&gt;
&lt;h2&gt;经典CNN设计&lt;/h2&gt;
&lt;p&gt;我们的CNN所需要调整的超参数主要有：卷积核的大小，channel数量，连接关系。而在经典的CNN则告诉我们&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;卷积核大小&amp;#x26;channel 数量&lt;/strong&gt; :对于相邻层之间保持整体的信息量不变(LeNets5,AlexNet)&lt;/li&gt;
&lt;li&gt;通过&lt;strong&gt;池化层来调整整体的信息量&lt;/strong&gt; ，并且比例大概为1/2左右(VGG-16)&lt;/li&gt;
&lt;li&gt;如何进行&lt;strong&gt;串联&lt;/strong&gt; （ResNets）&lt;/li&gt;
&lt;li&gt;1*1卷积核以及由此引发的&lt;strong&gt;并联关系&lt;/strong&gt; (GoogleNets)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于LeNets5,AlexNets, VGG-16都是比较早期的网络，如果我们将一个CNN看成是一堆电阻的连接的话，那么这三者就是研究每一个电阻的设计的。&lt;/p&gt;
&lt;h3&gt;LeNets5&lt;/h3&gt;
&lt;p&gt;废话少说，直接上网络图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果我们想要计算它的参数的话，可以发现，对于前面卷积层的参数是非常少的，对于一个有c个channels的，卷积核 $r&lt;em&gt;r$ 的卷积层，参数大小只有 $r&lt;/em&gt;r*c$ ,但是全连接层的参数量可以说是非常的大。于是&lt;strong&gt;对于全连接层，我们一般会下降到几百几千的时候再使用FC&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同时LeNets的设计使用了** Conv=&gt;Pool=&gt;Conv=&gt;Pool…**的结构，Pool可以认为是整合信息，而Conv是提取信息，对于两者交替进行的设计也是非常重要的想法。&lt;/p&gt;
&lt;p&gt;** LeNets5：**规定了CNN的整体结构，Conv&amp;#x26;Pool交替+最后的FC&lt;/p&gt;
&lt;h2&gt;AlexNets&lt;/h2&gt;
&lt;p&gt;AlexNets在CNN设计上没有特别突出的地方，但它是真正意义上的第一个深度神经网络，总共有60M的参数，总共10几层，可以在ImageNets上实现1000种图片分类正确率80%的效果。在15年的时候是非常牛B的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;AlexNets的关键不止于此。往年的神经网络基本都是使用sigmoid&amp;#x26;tanh(比较符合人脑神经元的激活条件)，但是AlexNets为了训练更深的网络，使用了非常多的** ReLU**函数，同时它还是第一个使用多个GPU进行训练的神经网络，就凭以上几点，AlexNets就以及非常NB了&lt;/p&gt;
&lt;p&gt;AlexNets: ** ReLU,深度NN,GPU training**&lt;/p&gt;
&lt;h3&gt;VGG16&lt;/h3&gt;
&lt;p&gt;VGG-16也是一个非常大的网络，在人脸识别种也有比较广泛的应用。它的创新点** 使用padding这个东西，卷积层不改变图像大小，只在池化层将整体大小缩小一倍**。同时它还提出了使用小卷积核来代替大卷积核的想法。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;之前的LeNets之类的都使用了很多 $5&lt;em&gt;5,7&lt;/em&gt;7$ 的卷积核，但是VGG16却告诉我们使用 $3*3$ 的卷积核也可以，不仅增加网络的深度，同时也减少了参数量。同时它还告诉了我们对于整体信息而言，需要保持以信息量的观点去设计网络&lt;/p&gt;
&lt;p&gt;小卷积核使得提取信息从小到大均可，这增加了网络的可迁移性，为之后的 Transform Learning提供了基础&lt;/p&gt;
&lt;p&gt;以上都是卷积核&amp;#x26;通道的设计思路，但是对于更深的网络，又该怎么办呢？以上网络都是一条路走到黑，如果我们想要将网路串联起来怎么办呢，ResNets以及GoogleNets就解答了这个问题&lt;/p&gt;
&lt;h3&gt;ResNets&lt;/h3&gt;
&lt;p&gt;ResNets个人认为是一个里程碑式的东西，之前所有的网络都是一条路走到黑，当层数上升的时候就会导致严重的梯度爆炸/消失现象，但是ResNets的skip式的连接结构就完全解决了这一情况&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;由图可以看到，我们的ResNets的一个Block中为&lt;strong&gt;conv1=&gt;conv2,output=conv2+conv1&lt;/strong&gt; 的结构，而其好处就是即使网络深度更深，也不会导致梯度消失。&lt;/p&gt;
&lt;p&gt;使用以上的skip path的方法我们就可以&lt;strong&gt;训练更深的网络&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;在ResNets的原始论文中（pass)中，我们可以对于skip path上不是直接连接过去的，而是使用了两种不同模块——Identity Block块(直接相加，保持网络稳定)以及Conv Block(卷积操作)，最后我们设计了ResNet-18,34,50,101,152层的网络，其大小分别为11M,21M,25.5M,44.5M,60.2M&lt;/p&gt;
&lt;h3&gt;$1*1$ 卷积核&lt;/h3&gt;
&lt;p&gt;在介绍GoogleNet之前，有一个常见的操作叫 $1*1$ 卷积核。&lt;/p&gt;
&lt;p&gt;$1&lt;em&gt;1$ 卷积核看上去没有什么用处，但是每一个 $1&lt;/em&gt;1$ 卷积核相当于对所有在这个位置上的图片的特征进行重组，从而对于&lt;strong&gt;图片特征进行调整&lt;/strong&gt; ，而如果我们使用多个 $1*1$ 卷积核，那么就是可以对于通道数量进行调整&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Google Net&lt;/h3&gt;
&lt;p&gt;Google Net启发与我们对于卷积核的大小而言， $1&lt;em&gt;1,3&lt;/em&gt;3,5*5$ 都是一种选择，甚至池化层也是一种选择，与其思考该如何将进行选择，我们可以考虑将这些东西全都拍到一块&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;即为通过padding保持在使用 $c_r$ 个 $r*r$ 卷积之后图片大小不变,将所有的 $c_r$ 都拍到一起，形成一个同样大小的东西。&lt;/p&gt;
&lt;p&gt;于是google net使用若干个不同的这样的inception模块并组合起来，发现最后的效果非常好。&lt;/p&gt;
&lt;p&gt;综上所述，我们对于设计网络的时候可以考虑对他们进行&lt;strong&gt;transfer training&lt;/strong&gt;,即为固定网络的前面若干层，直到最后的几层换成我们自行设计的网络进行训练。而我们自己设计的时候需要考虑** 信息量的传递关系，可以通过inception block以及skip path的途径**来加深我们的网络并提升性能。这些都是可以考虑的方案。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C4W3&amp;4:CNN应用——人脸识别，物体探测与风格转换以及背后的原理</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c4w3-4-cnn-apps-face-recog-style-transfer/cs230-c4w3-4-cnn-apps-face-recog-style-transfer</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c4w3-4-cnn-apps-face-recog-style-transfer/cs230-c4w3-4-cnn-apps-face-recog-style-transfer</guid><description>CS230 C4W3&amp;4:CNN应用——人脸识别，物体探测与风格转换以及背后的原理</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;之前我们了解了CNN设计的常见思路，而接下来我们将会介绍人脸识别，图像识别等方面一些特别的设计结构，并由此对CNN中的&lt;strong&gt;卷积&lt;/strong&gt; 有更深刻的理解。&lt;/p&gt;
&lt;h2&gt;人脸识别&lt;/h2&gt;
&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p&gt;我们有一个由人脸照片组成的一个数据库，&lt;strong&gt;每人都只有一张图片记录&lt;/strong&gt; ，我们输入一张图片，希望能判断这个图片上的人是否在这些人脸中&lt;/p&gt;
&lt;h3&gt;One-shot Learning&lt;/h3&gt;
&lt;p&gt;对于这个问题的第一反应肯定是对两个图片直接计算范数，但是这个肯定是不可以的。因为外部的环境(白天，晚上等)会让图片看上去非常的不一样。&lt;/p&gt;
&lt;p&gt;同时我们注意到如果使用&lt;strong&gt;独热编码&lt;/strong&gt; 的话，网络每一次的输出都是通过一个softmax得到一个结果的话，那么每次输入一个人都要重新训练这个网络，收益太低。而且我们对于一个人只有一张图片，无法进行大规模的训练。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;于是我们网络的目标是:&lt;strong&gt;可以提取一张图片上关于人脸的信息，以较高的正确率与其他人的照片进行比较&lt;/strong&gt; ，借鉴&lt;strong&gt;身份证&lt;/strong&gt; 的想法，我们可以考虑将每张人脸转换成一个&lt;strong&gt;向量&lt;/strong&gt; 进行比较&lt;/p&gt;
&lt;h3&gt;Siamese Network&lt;/h3&gt;
&lt;p&gt;siamese Network就是使用这样的方法，它可以将每一张输入的人脸经过一个CNN之后，不是最后用softmax进行分类，而是&lt;strong&gt;直接使用最后FC的输出(高维向量)&lt;/strong&gt; 来表示人脸的信息&lt;/p&gt;
&lt;p&gt;假设对于输入 $x^1$ 时输出向量为 $f(x^1)$ ,我们对于不同图片的比较，直接使用范数比较 $d(x^1,x^2)=||f(x^1)-f(x^2)||^2$ 。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若 $d(x^1,x^2)&amp;#x3C;\tau$ ，那么表示这两个人的脸非常像，可以认为是同一个人&lt;/li&gt;
&lt;li&gt;若 $d(x^1,x^2)&gt;\tau$ ,可以认为不是同一个人&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于训练这个网路的时候，我们希望 $f(x^1)$ 可以对长相相近的人的图片进行奖励，而对于长相不同的进行乘法。于是对于每一组的训练数据，由人A的图片 $A_1$ ，A的另外一张图片 $A_2$ ,以及另外一个人的图片 $B$ 组成&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;损失函数&lt;/strong&gt; $L=||f(A_1)-f(A_2)||^2-||f(A_1)-f(B)||^2$ 就可以做到奖励相同惩罚不同。&lt;/p&gt;
&lt;p&gt;将若干组 $(A_1,A_2,B)$ 输入到网络中，经过训练之后得到网络 $f(x)$ ,而预测的时候只要输入一个图片 $X$ ，将 $f(X)$ 与数据库中的东西进行比较&lt;/p&gt;
&lt;h2&gt;图像形式转换&lt;/h2&gt;
&lt;p&gt;举个例子，我们希望有一张梵高的图片，还有一张USTC的照片，我们想要用梵高作画的风格去画USTC的这个画, 希望可以编写一个网络去实现。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;由于我们学过了MIT 6.S184了，我们在产生图片的时候，仍然是想要让图片从原始的噪声变成符合要求的状态，虽然本题我们不会使用扩散模型(虽然也可以，对于那张梵高的图片以及USTC变成条件y，然后进行图片生成，但是过于麻烦了。）&lt;/p&gt;
&lt;h3&gt;问题思路&lt;/h3&gt;
&lt;p&gt;我们发现** 风格&amp;#x26;内容**都是物体的特征，只是这个是不同方面的，考虑到这些都是通过图片去进行提取的，使用CNN去进行这个方面的提取即可。&lt;/p&gt;
&lt;p&gt;结合扩散模型的变化的思路，我们的思路就是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从噪声出发，沿着某个CNN，直到某一层，设计一个损失函数 $J(Content, Style, Present)$ 来比较三张图片&lt;/li&gt;
&lt;li&gt;不是对参数进行梯度下降，而是对于目前的图片Present进行梯度下降，每一个iteration对于当前的图片进行调整，使得损失函数更小&lt;/li&gt;
&lt;li&gt;最后得到想要的图片。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;称我们当前的图片为 $G$ ,风格图片为 $S$ ,内容图片为 $C$ ,则损失函数为 $J(G)=\alpha* J(C,G) +\beta* J(S,G)$&lt;/p&gt;
&lt;h3&gt;Content Cost Function&lt;/h3&gt;
&lt;p&gt;评价我们想要生成的图片的内容，对于内容而言，风格的变化不会带来非常巨大的差距。&lt;/p&gt;
&lt;p&gt;于是我们网络的话可以使用迁移性能较好的VGG，生成过程中，对于C,G中的第l层输出 $a^{(c)[l]},a^{(G)[l]}$ 使用 $J_l(C,G)=\dfrac{1}{2} ||a^{(c)[l]}-a^{(G)[l]}||^2$ 可以衡量这个作为内容上的差异。&lt;/p&gt;
&lt;p&gt;从而为每一层添加一个权重  $J(C,G)=\Sigma_l \lambda^l J_l(C,G)$ 即为我们的&lt;strong&gt;内容损失函数&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Style Cost Function&lt;/h3&gt;
&lt;p&gt;首先我们需要明确风格是什么，两张图片都是由梵高画的，如果将他们分别拆分成对应的RGB三原色，对于** 一张图片三种颜色的组合方式应该和另外一张相同**，而组合方式翻译过来也就是** 相同位置，不同通道之间的关系**.&lt;/p&gt;
&lt;p&gt;于是我们的风格也就是不同通道之间的关系。对于不同通道之间的关系，可以认为每一个通道对应的2D图片都是空间上的一个向量，如果我们的关系比较接近，我们的方向应该相同。只是我们的空间维度为 $r*r$&lt;/p&gt;
&lt;p&gt;维的。而方向就是点乘。于是对于一张图片 $a_{ijk}^l$ 表示网络的第l层，ij为像素点在图片上的位置坐标，k表示这是第几个channel,&lt;strong&gt;Gram Matrix&lt;/strong&gt; 为 ${G_{kk&apos;}^l} = {\displaystyle \sum_{i=1}^{n_H} \sum_{j=1}^{n_W} a^l_{ijk}\cdot a^l_{ijk&apos;}}$ 即为描述&lt;strong&gt;第k和k’个通道的关系。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而我们第l层的Style Cost Function为&lt;/p&gt;
&lt;p&gt;$J_{style}^l{S,G}=\dfrac{1}{(2n_H^ln_W^l n_C^l)^2} \Sigma_k \Sigma_{k&apos;}(G_{kk&apos;}^{l[G]}-G_{kk&apos;}^{l[S]})^2$ ,最后的损失函数为 $J(S,G)=\Sigma_l \lambda^l J_l(S,G)$&lt;/p&gt;
&lt;p&gt;将以上的内容整合起来就可以对于图片进行风格上的转换了。&lt;/p&gt;
&lt;h2&gt;物体识别&lt;/h2&gt;
&lt;h3&gt;问题描述&lt;/h3&gt;
&lt;p&gt;对于一张图片，我们希望能识别出来其中所有的汽车，飞机，行人…并且在其周围画上一个边框。&lt;/p&gt;
&lt;p&gt;对于这个问题，我们可以拆分成若干个步骤（1）对于一个图片中只有一个物体时如何识别 （2）如何分别识别图片不同位置物体 （3) 图片有所重叠怎么办 (4)最后整合起来&lt;/p&gt;
&lt;h3&gt;One Picture&amp;#x26;One object&lt;/h3&gt;
&lt;p&gt;前面两个案例中，对于CNN都是使用了其提取特征的能力，而对于图片分类的话最后是使用softmax进行单个输出。而该问题中，显然输出y应该包含：（1）物体的边界 以及中心 （2）这张图片上有物体/没有物体 (3）如果有物体的话那么每一种物体的概率即为 $y=[(b_x,b_y,b_H,b_W),p_{object},c_1,c_2,.....c_n]$ 这些输出。网络结构的话只要把最后一层的softmax改成一个全连接层。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;于是训练的时候只需要扔给网络一堆的这样的(图片，输出)的pair，** 将训练数据集做好**,然后进行梯度下降就可以了。（类似的，如果我们想要对于人脸的特征点进行采样，只要把相应的数据集做好即可进行训练）&lt;/p&gt;
&lt;p&gt;我们如果要识别一张图片上的多个物体，一种想法是使用一个滑块，在图片上不断的移动，从而可以识别到不同位置的物体，但是如果实现（切割图片，输入，输出，处理得到结果）的话，非常耗费算力，相应的，我们可以直接将** 卷积核应用到整个图片上**，假设最一开始是一个 $14&lt;em&gt;14&lt;/em&gt;3$ 的图片，得到一个 $1&lt;em&gt;1&lt;/em&gt;k$ 的输出，将这个卷积神经网络应用到一个 $28&lt;em&gt;28&lt;/em&gt;3$ 的图片上，最后是一个 $8&lt;em&gt;8&lt;/em&gt;k$ 的输出，对于每一个 $1&lt;em&gt;1&lt;/em&gt;k$ 的卷积核都表示一个 $14&lt;em&gt;14&lt;/em&gt;3$ 区域对应的输出。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;使用这种sliding window的方法可以精确的找到所有的物体，但是缺点是太耗费算力，而且由于太精确了，有可能画出来的框框不是我们想要的。&lt;/p&gt;
&lt;h3&gt;YOLO 算法&lt;/h3&gt;
&lt;p&gt;YOLO是物体识别的主流算法，接下来就其15年的v1来介绍一下。&lt;/p&gt;
&lt;h3&gt;识别可能的物体&lt;/h3&gt;
&lt;p&gt;YOLO v1的假设是对于一个图片上不会有一小块的位置上有特别特别多的需要识别的物体。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;YOLO与sliding window不同，sliding window是将以1为stride进行移动，如果我们的视野域为 $a&lt;em&gt;a$ ,而图片大小为 $b&lt;/em&gt;b$ ,那么总共就需要计算 $(b-a+1)^2a^2$ 次，这实在是太大了。而我们的YOLO算法是**将 $b&lt;em&gt;b$ 的图片分割成 $r&lt;/em&gt;r$ 个”cell”**对于每一个cell（图片的一个局部）而言都进行物体的识别，最后得到一个 $r*r$ 个物体的边框&lt;/p&gt;
&lt;h3&gt;合并区域&lt;/h3&gt;
&lt;p&gt;上一个步骤中我们每一个cell都会给出一个物的边框，但是如果有的物体在多个cell中都有出现，那么就需要&lt;strong&gt;对边框进行合并&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;为了判断那些边框可以进行合并，需要引入测算边框交叉部分的 $\eta=\dfrac{S_{intersection}}{S_{union}}$ ，其中 $S_{intersection}$ 是两个边框的交叉部分面积， $S_{union}$ 是整体的面积。&lt;/p&gt;
&lt;p&gt;假设我们现在来合并所有的种类为c的物体的边框&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先对于将所有的 $p_c&gt;0.6$ 的边框给拿出来，并且把别的边框给丢弃&lt;/li&gt;
&lt;li&gt;从剩余的边框中取出来 $p_c$ 最大的，将余下来的边框中满足 $\eta=\dfrac{S_{intersection}}{S_{union}}&gt;0.5$ 的边框给合并到这一个中&lt;/li&gt;
&lt;li&gt;重复第二步，得到所有种类c的物体的边框，对于别的c而言采取同样的操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过以上的步骤我们可以成功的对于边框进行合并。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;单个cell多个物体&lt;/h3&gt;
&lt;p&gt;有的时候，同一个cell中会出现多个物体，比如一个人站在汽车的前方，此时我们就需要对单个cell的输出进行一些改变。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_08.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于单个的cell,之前我们的输出为 $y=[p_c,b_x,b_y,b_h,b_w,c1,c2,c3]$ ,而此时我们想要探测多个物体，只需要使用 $y_1=[p_c,b_x,b_y,b_h,b_w,c1,c2,c3],y_2=[p_c,b_x,b_y,b_h,b_w,c1,c2,c3]$&lt;br&gt;
即可&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是这样的问题是两个输出可能会探测到同一个物体上，而我们想要探测不同的物体，这两个物体又有不同的形状，结合上面的交叉部分探测的观点，可以&lt;strong&gt;事先规定若干个不同大小的anchor box， $y_1$ 存储和anchor box1的 $\eta&gt;0.5$ 的物体， $y_2$ 同理&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;最后我们只需要&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先对于每一个cell而言，得到若干个anchor box对应的边框&lt;/li&gt;
&lt;li&gt;排除 $p_c&amp;#x3C;0.6$ 的边框并进行合并操作&lt;/li&gt;
&lt;li&gt;最后得到的就是就是我们的答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上就是CNN在实际中的一些常见应用，可以发现CNN对于&lt;strong&gt;图形的特征提取&lt;/strong&gt; 效果非常好，尤其是“从浅层到深层次提取深度不断增加”的想法，这种特征提取的思想是非常的关键的。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230 C5:RNN以及其应用简介绍</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c5-rnn-apps/cs230-c5-rnn-apps</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-c5-rnn-apps/cs230-c5-rnn-apps</guid><description>CS230 C5:RNN以及其应用简介绍</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS230的最后一块内容是介绍关于RNN的，个人感觉Andrew Ng在RNN网络的介绍上非常详细，但是对于NLP&amp;#x26;LLM部分就显得不太行了，本文中我们将会就RNN网络的来龙去脉进行介绍，对于RNN的应用我们将会留到cs224n中进行介绍。&lt;/p&gt;
&lt;h2&gt;RNN&lt;/h2&gt;
&lt;p&gt;我们的需要对一段语句进行处理，对于输入的形式为单词 $(x^1,x^2,....x^n|x^{last})$ ，其中 $x^i$ 为一个单词的独热编码。通常对于输入的最后我们会添加一个 $x^{last}$ 来标志一段话的结束。&lt;/p&gt;
&lt;h3&gt;Basic RNN(输入=输出)&lt;/h3&gt;
&lt;p&gt;RNN的主要想法是将单词依次输入，并且使用变量 $a^t$ 来记录t时刻输入后对于&lt;strong&gt;语句语意&lt;/strong&gt; 的记录。按照输入顺序依次罗列，更新 $a^t$ 并且输出 $y^i$ ，这种顺序的输入结构就是RNN,其网络结构为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前向传播&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;t时刻的输入 $a^{t-1},x^t$ 输出为 $a^t,y^t$ 。起初 $a^0=0$&lt;/li&gt;
&lt;li&gt;t时刻对于 $a^t,y^t$ 进行更新&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$a^t=g(W_{aa} a^{t-1}+W_{ax} x^t+b_a), g(x)=tanh/relu/...(x)$&lt;/p&gt;
&lt;p&gt;$y^t=f(W_{ya}a^t+b_y), f=softmax$&lt;/p&gt;
&lt;p&gt;由此对于一段语言&lt;strong&gt;输入便可以得到相应的输出，同时可以记录当前的语句的语意&lt;/strong&gt; 思，这便是最基本的RNN.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反向传播&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们对于任意时刻t而言， $\hat{y_t}=[p_1,p_2,...p_n]$ 为每一个单词出现的概率，而如果我们有标签数据 $y_t$ 的话，可以有损失函数 $L^t(\hat{y^t},y^t)=-\Sigma_i y_t^i log(\hat{y_t^i}),\quad L(\hat{y},y)=\Sigma_{t=1}^TL^t(\hat{y^t},y^t)$ 于是只要做好** 标签数据**即可实现最为基础的RNN。&lt;/p&gt;
&lt;h3&gt;Encoder &amp;#x26; Decoder RNN&lt;/h3&gt;
&lt;p&gt;在机器翻译的时候，可能不一定是一个单词输入对应一个单词输出。一般的，我们需要理解前一段话的语义(Encoder)之后再进行整体的翻译部分(Decoder)。于是我们需要在原有的RNN上进行改进。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder&lt;/strong&gt; ：对于输入部分，我们不需要有输出，只需要对于 $a^t$ 进行更新，即为 $a^t=g(W_{aa} a^{t-1}+W_{ax} x^t+b_a), g(x)=tanh/relu/...(x)$ ，直到输入停止&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decoder&lt;/strong&gt; ：对于输出部分，由于 $a^t$ 记录的是之前的状态，对于此部分的输入为 $a^T$ 。此时我们没有了x这个东西，但是可以将 &lt;strong&gt;上一个时刻的输出作为下一个时刻的输入&lt;/strong&gt;,图形以及数学表示为&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Decoder RNN给了我们一个提示，a为记录语句状态的，而如果需要输出，将最后时刻的a经** 过想要的结构**(可以是Fully Connect,也可以是别的结构)，最后得到想要的输出。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;RNN训练时的常见问题&lt;/h3&gt;
&lt;p&gt;再来看一下我们的网络结构图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以发现这个过程中有一个非常长的传播的路径，于是我们再进行反向传播的时候就非常容易发生** 梯度爆炸或者消失**。于是这个过程中就需要（1）梯度裁剪或者放大 （2）batch-norm可以对整体的梯度进行调整 (3)合适的初始化&lt;/p&gt;
&lt;p&gt;对于以上的RNN而言，每一个输入对于我们的记忆的影响都是一样的，但是就想”a”,“is”之类的词语和一些动词，名词的作用是不相同的，于是我们就需要对于** 记忆力机制进行改进**。我们使用** 门&lt;strong&gt;来控制记忆的遗忘，更新，不变(GRU&amp;#x26;LSTM),同时我们的语义理解应该是区域性的而不是顺序的，因此就需要使用&lt;/strong&gt; 双向RNN**来控制记忆。&lt;/p&gt;
&lt;h3&gt;GRU(Gated Recurrent Unit)&lt;/h3&gt;
&lt;p&gt;GRU的核心思想:对于记忆有两个状态,** 更新&lt;strong&gt;和&lt;/strong&gt; 维持**，我们通过设置一个“门”(也就是一个变量)来控制这两者。&lt;/p&gt;
&lt;p&gt;GRU对于t时刻的输入 $a^t,x^t$ 想要得到下一个时刻的输出 $a^{t+1}$&lt;/p&gt;
&lt;p&gt;** basic GRU**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于门的实现，我们会使用sigmoid得到一个**“gate”** :通过0&amp;#x26;1来决定是否要进行更新，具体数学为 $g^t=\sigma(W_{gx}x^t+W_{ga}a^t+b_{g})$&lt;/li&gt;
&lt;li&gt;而我们对于记忆的更新，首先得到一个&lt;strong&gt;备选&lt;/strong&gt; 的更新后的记忆 $\tilde{a^t}=tanh(W_{ax}x^t+W_{aa}a^t+b_{a})$&lt;/li&gt;
&lt;li&gt;最后根据门来决定是维持原有的记忆还是更新记忆：如果gate为false，那么就将 $a^t$ 赋给 $a^{t+1}$ 。反之将备选的记忆赋值给 $a^{t+1}$ 。即为 $a^{t+1}=g^t\odot \tilde{a^t}+(1-g^t)\odot a^t$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;图形化表示即为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fully GRU&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;考虑到有的时候有的输入会突然对整体的意思产生非常大的影响，如否定词会直接取反整句的意思，于是我们需要对于 $\tilde{a^t}$ 的输入 $a^t$ 选项添加另外一个门来处理&lt;/p&gt;
&lt;p&gt;$ \begin{align*}     \tilde{a}^{} &amp;#x26;= \tanh(W_c [\Gamma_r \odot a^{}, x^{}] + b_c) \     \Gamma_u &amp;#x26;= \sigma(W_u [a^{}, x^{}] + b_u) \     \Gamma_r &amp;#x26;= \sigma(W_r [a^{}, x^{}] + b_r) \     a^{} &amp;#x26;= \Gamma_u \odot \tilde{a}^{} + (1 - \Gamma_u) \odot a^{} \end{align*} $&lt;/p&gt;
&lt;p&gt;使用以上方法，总共只要用原有RNN的2-3倍的参数就有比较好的效果。是一种速度比较快的方法。&lt;/p&gt;
&lt;h3&gt;LSTM(Long short term memory)&lt;/h3&gt;
&lt;p&gt;LSTM是一种更加复杂的记忆力机制，在英文输入的时候，有的时候可能会先说一堆废话，然后“言归正传”，或者是最一开始有一个总起句子，需要进行长时间的记忆，为了实现这种长短记忆力机制，我们需要设计更加复杂的结构。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于&lt;strong&gt;长短记忆力&lt;/strong&gt; ：之前我们都是使用单个记忆力 $a^t$ 进行记忆，接下来我们将会使用 $a^t$ 来表示短期的记忆，而 $c^t$ 表示长期的记忆&lt;/li&gt;
&lt;li&gt;LSTM设置了&lt;strong&gt;3个状态&lt;/strong&gt; :&lt;strong&gt;遗忘过去内容并添加新内容，遗忘所有的内容，保持现有的内容&lt;/strong&gt; 。因此我们需要一个控制“遗忘过去”，“遗忘现在”的门，并且最后需要将两个门整合起来，有一个控制”遗忘所有内容”的门。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$\begin{align} \Gamma_{past} &amp;#x26;= \sigma(W_{past} [a^{}, x^{}] + b_{past}) \     \Gamma_{present} &amp;#x26;= \sigma(W_{present} [a^{}, x^{}] + b_{present}) \     \Gamma_{all} &amp;#x26;= \sigma(W_{all} [a^{}, x^{}] + b_{all}) \end{align} $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于长期&amp;#x26;短期记忆 $c^t,a^t$&lt;br&gt;
的更新思路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ \tilde{c^t}= tanh(W_{c} [a^{}, x^{}] + b_{c})\ c^t=\Gamma_{past} \odot \tilde{c^t}+\Gamma_{present} \odot \tilde{c^t}\ a^t=\Gamma_{all}\odot c^t $&lt;/p&gt;
&lt;p&gt;通过以上的步骤就可以做到更新&lt;strong&gt;长期的记忆&lt;/strong&gt; ，并且由此得到&lt;strong&gt;短期的记忆&lt;/strong&gt; 的更新。其图形化表示为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;B-RNN&lt;/h3&gt;
&lt;p&gt;之前我们所有的输出都是线性输入，每一个单词的理解只会根据其前文的内容，但是真实情况是会根据上下文进行理解的。于是我们会使用双向RNN: 先从头到尾进行阅读，得到记忆 $a^t$ ,然后从尾到头读，得到记忆 $b^t$ ,最后一起得到最后的输出从图片上可以看出来，这个网络实际上就是两个RNN拼接起来的结果。&lt;/p&gt;
&lt;p&gt;以上就是RNN的基本结构部分，对于传统的RNN，个人感觉最重要的是&lt;strong&gt;记忆力&lt;/strong&gt; 的实现与理解，尤其是长短期的记忆力，以后的transformer中即使有非常长的文本，我们没有办法全部输入进网络，需要做的仍然是通过记忆力的方式去进行记忆。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;RNN应用&lt;/h2&gt;
&lt;p&gt;RNN第一个应用就是对于一段语言的处理，而对于语言的处理，即为每一个单词的表示形式从最一开始的&lt;strong&gt;独热编码&lt;/strong&gt; 变为&lt;strong&gt;Word Embedding&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;对于变成了word Embedding之后的处理我们现在使用的是Transformer。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transformer&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;self attention:其中(Q,K,V)可以认为是我们对于每一个单词的理解认为是一个查询，而查询会影响到我们对于这个单词的理解方式，最后加上相应的权重V,即为 $Attention(Q,K,V)=softmax(\dfrac{QK^T}{\sqrt{d_k}})V$&lt;br&gt;
这里的（Q,K,V)为对于输入单词经过相应的矩阵 $W^Q,W^K,W^V$ 产生的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;self attention的输入是&lt;strong&gt;单词的embedding&lt;/strong&gt; ，而输出为在经过attention处理之后的应该被认识的方式(&lt;strong&gt;每一个单词对应着一个向量&lt;/strong&gt; )&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-Head attention，类似于多重卷积核，对于self attention我们使用多个，就可以得到对于每一个单词的不同的理解方式，，最后经过一个全连接，得到&lt;strong&gt;对于每一个单词的理解方式(一个向量)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Transformer:我们不考虑add&amp;#x26;norm，即为&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Encoder部分&lt;/strong&gt; ：单词输入，经过multi-hear attention之后得到一些输出&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Decoder部分&lt;/strong&gt; ：输入为之前的单词，Encoder对于单词的理解，经过Attention后的一些基本知识，以上的部分经过Attention之后concat起来，最后经过一个softmax得到输出。&lt;/p&gt;
&lt;p&gt;具体的部分我们留到cs224n中详细讨论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Word Embedding&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而对于word Embedding而言，我们知道了它是非常重要的，每一个单词对应的向量就表示了它的意思在不同维度的比重。&lt;/p&gt;
&lt;p&gt;而训练word Embedding的数据集的构建为从一段文字中挑选的若干个，对于这一块的训练过程我留到CS224n去讨论。&lt;/p&gt;
&lt;p&gt;机器翻译的评判标准我们会使用Bleu score，简单而言就是分别考察1个单词，2个单词。。。多个单词预测成功的概率并进行奖励惩罚。&lt;/p&gt;
&lt;p&gt;对于RNN的应用远远不止机器翻译一个领域，它还可以应用到任何线性输入的东西之中。在cs224n中我们将会详细学习这一部分的内容。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS230Pre: MiniConda&amp;Python环境配置</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-pre-miniconda-python-env/cs230-pre-miniconda-python-env</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs230-pre-miniconda-python-env/cs230-pre-miniconda-python-env</guid><description>CS230Pre: MiniConda&amp;Python环境配置</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;conda是一款用于管理python环境与包的管理器，尤其是对于不同项目需要使用不同的python环境，conda就可以方便的进行隔离。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Step 1:安装conda&lt;/h2&gt;
&lt;p&gt;对于个人应用的话下载miniconda就可以了&lt;/p&gt;
&lt;p&gt;个人建议从官网&lt;/p&gt;
&lt;p&gt;或者从清华源&lt;/p&gt;
&lt;p&gt;上下载和电脑项配的包，将其安装在d盘就可以了。&lt;/p&gt;
&lt;h2&gt;Step 2:配置conda环境&lt;/h2&gt;
&lt;p&gt;这篇知乎文章讲的挺全的&lt;/p&gt;
&lt;h2&gt;Step 3:配置开发环境&lt;/h2&gt;
&lt;p&gt;如果你以及完成了以上的两步，那么在输入了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda create --name myenv python=3.9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后，你就在conda的安装目录同级出现一个_env文件夹，在这个文件夹里面会有一个叫myenv的文件夹，里面存放着所有的python包&lt;/p&gt;
&lt;p&gt;在安装前需要先进入这个环境&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda activate myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;退出的话为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda deactivate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于安装python包的话，个人还是喜欢使用pip去安装，比如你想要安装&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是安装numpy包&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install numpy
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果是需要指定版本，并且通过清华源去安装，为&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install numpy==... -i https://pypi.tuna.tsinghua.edu.cn/simple/
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;卸载numpy&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip uninstall numpy
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果你想要安装requirements.txt中的包（注意其中每一行为一个包）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 4(Optional)Vscode配置python&lt;/h2&gt;
&lt;p&gt;以下这篇文章中讲了配置的问题&lt;/p&gt;
&lt;p&gt;其余的在这篇文章中讲的挺好，但是对于在vscode中激活python环境&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;点击这个圈的地方，然后就可以在上方发现本电脑的环境以及自己配置的各个隔离的环境。选择好后就对于python文件在VScode中直接执行就可以了。&lt;/p&gt;
&lt;p&gt;希望这篇文章可以为想要学习cs230的同学们提供一点点帮助&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>Stanford CS230食用指南</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/stanford-cs230-usage-guide/stanford-cs230-usage-guide</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/stanford-cs230-usage-guide/stanford-cs230-usage-guide</guid><description>Stanford CS230食用指南</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CS230虽然说是讲关于Deep Learning的，但是这门课程包括了很多的课后资源（coursera上的视频以及作业），上课更多的是关于大局观上的介绍。接下来我就个人的理解来整理一下学习Deep Learning的资源以及食用方法。&lt;/p&gt;
&lt;h2&gt;主要资源&lt;/h2&gt;
&lt;p&gt;1.CS230 Lecture 2018Fall 视频课（10个lecture）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;视频资源&lt;/strong&gt; 为直接在b站上搜cs230第一个就是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;github仓库&lt;/strong&gt; 中包含课堂的PPT，期中期末的考试题目，仓库名为cs230-2018-autumn&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;2.Coursera上的Deep learning specialization (5节课，每节课大概4h左右）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;视频资源&lt;/strong&gt; 为b站搜索“Deep Learning Specialization 吴恩达 Andrew Ng”的视频&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;github&lt;/strong&gt; 仓库中包含written homework（quizzes）以及coding homework(programming assignments),仓库为amanchadha的coursera-deep-learning-specialization&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;食用指南&lt;/h2&gt;
&lt;p&gt;1.cs230的核心内容（干货）在coursera的课上，具体介绍了&lt;/p&gt;
&lt;p&gt;（1）神经网络架构 （2）超参数优化方法 （3）体系化建构 （4）CNN（CNN,Resnet） (5)RNN(RNN, LSTM)&lt;/p&gt;
&lt;p&gt;这里的programming assignments写的非常好，一定要认真完成，会让你具体实现这些功能并在课堂的基础上进行拓展，但是从github上clone下来的jupyter notebook中作业都是给你写好了的，只要扔给ai把“start coding”以及“end coding”中间的内容删除就可以了。&lt;/p&gt;
&lt;p&gt;2.cs230 Lecture内容：&lt;/p&gt;
&lt;p&gt;(1-2）对DL的基本介绍（examples, history）&lt;/p&gt;
&lt;p&gt;(3,8) 大局观（水）&lt;/p&gt;
&lt;p&gt;(4)GAN介绍&lt;/p&gt;
&lt;p&gt;(6,7)如何做研究以及读论文&lt;/p&gt;
&lt;p&gt;(9,10)关于NN与强化学习的结合&lt;/p&gt;
&lt;p&gt;以上是对于课程内容的总结，希望大家（以及自己）能有所收获。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>CS229:无监督学习（二）——概率学习：高斯混合算法，EM算法以及Factor analysis</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-unsupl-2-gmm-em-factor/cs229-unsupl-2-gmm-em-factor</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/cs229-unsupl-2-gmm-em-factor/cs229-unsupl-2-gmm-em-factor</guid><description>CS229:无监督学习（二）——概率学习：高斯混合算法，EM算法以及Factor analysis</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一篇文章中我们学习了无监督学习中不含概率假设的部分，但是使用MLE进行预测仍然是非常重要的预测方法，而之前对于无标签数据是通过&lt;strong&gt;假设距离&lt;/strong&gt; 作为衡量因素，概率学习则是通过假设给定  $z,\phi$  情况下的  $P(x|z^i,\phi)$  去实现的，为了更加方便计算，我们会使用&lt;strong&gt;EM algorithm&lt;/strong&gt; 去简化计算MLE的过程，但我们通过计算发现这只适用于训练数据量较大的情况，而对于数据维度比较大时，我们会使用&lt;strong&gt;Factor analysis&lt;/strong&gt; 去代替分析进行特征提取。&lt;/p&gt;
&lt;h2&gt;Mixture of Gaussian&lt;/h2&gt;
&lt;p&gt;仍然考虑对于给定  $(x^1,x^2,...x^n)$  ,将其分成k类的问题&lt;/p&gt;
&lt;p&gt;对于之前&lt;strong&gt;Naive Bayes&lt;/strong&gt; 的时候，我们是做出  $z^i$  ~  $Ber(\phi)$  的假设，对于  $P(x^i|z,\phi)$  可以通过训练数据去学习，而对于Mixture of Gaussian,我们需要对于  $P(x^i|z,\phi)$  做出更多的假设才能得到相应的模型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assumption&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$z^i$  ~  $Multinomial(\phi_1,\phi_2,...\phi_k)$  ,其中  $\Sigma^k_{i=1} \phi_i=1$&lt;/li&gt;
&lt;li&gt;$x|z^i,\phi$  ~  $N(\mu_i,\Sigma_i)$  ,这个是合理的假设，对于一般的数据分布都是正态分布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从而代入&lt;/p&gt;
&lt;p&gt;$$$ \begin{aligned} l(\phi,x)&amp;#x26;=log(\Pi^m_{i=1}P(x^i,\phi))\ &amp;#x26;=log(\Pi^m_{i=1}\Sigma^k_{j=1}P(x^i|z^j,\phi)P(z^j|\phi))\ &amp;#x26;=\Sigma^m_{i=1}log(\Sigma^k_{j=1}P(x^i|z^j,\phi)P(z^j|\phi))) \end{aligned} $$$&lt;/p&gt;
&lt;h3&gt;How to solve the parameters?&lt;/h3&gt;
&lt;p&gt;如果我们已知  $P(z|x^i,\phi)$  在supervised learning 中可以通过训练数据去得到，此时的参数为&lt;/p&gt;
&lt;p&gt;$$$ \begin{aligned} \phi_j &amp;#x26;= \frac{1}{m} \sum_{i=1}^m 1{z^{(i)} = j}, \ \mu_j &amp;#x26;= \frac{\sum_{i=1}^m 1{z^{(i)} = j} x^{(i)}}{\sum_{i=1}^m 1{z^{(i)} = j}}, \ \Sigma_j &amp;#x26;= \frac{\sum_{i=1}^m 1{z^{(i)} = j} (x^{(i)} - \mu_j)(x^{(i)} - \mu_j)^T}{\sum_{i=1}^m 1{z^{(i)} = j}}. \end{aligned} $$$&lt;/p&gt;
&lt;p&gt;而在此时，我们仍然是使用假设的方法：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;求解Mixture of Gaussian&lt;/p&gt;
&lt;p&gt;对于每一个循环中我们假设了  $P(z^i=j|x^i,\phi)=\dfrac{P(x^i|z^i=j,\phi)P(z^i=j,\phi)}{\Sigma^k_{i=1}P(x^i|z^i=j,\phi)P(z^i=j,\phi)}$  ,并保持它在该循环不变，更新相应的参数，最后该表达式会收敛到确定的参数值。&lt;/p&gt;
&lt;p&gt;通过以上的步骤我们大致的得到了一个结果，但是至于为什么会收敛以及EM steps 的一般形式呢？&lt;/p&gt;
&lt;h2&gt;EM algorithm&lt;/h2&gt;
&lt;h3&gt;数学原理&lt;/h3&gt;
&lt;p&gt;$Jenson\ Inequality:E(f(x))&gt;f(E(x))$  对于任何的凹函数成立，反之符号相反&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;琴生不等式&lt;/strong&gt; 在高中数学竞赛中是一个常识性的结论，对于其数学证明可以参见《数学奥林匹克小丛书高中卷——均值不等式与柯西不等式》第一章的例题部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;几何直观&lt;/strong&gt; 上，以一个二次函数为例，就是对于凹函数，如果控制x1+x2的值不变，想要将  $f(x_1)+f(x_2)$  的值更大，那么两者就要离得越远&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Jenson inequality&lt;/p&gt;
&lt;h3&gt;EM algorithm:&lt;/h3&gt;
&lt;p&gt;假设对于给定  $x^i$  ,  $z^i$  值的分布  $Q_i(z),\Sigma_zQ_i(z)=1$  ,则&lt;/p&gt;
&lt;p&gt;$\begin{aligned}  \sum_{i} \log p(x^{(i)}; \theta)&amp;#x26; = \sum_{i} \log \sum_{z^{(i)}} p(x^{(i)}, z^{(i)}; \theta) \ &amp;#x26;= \sum_{i} \log \sum_{z^{(i)}} Q_i(z^{(i)}) \frac{p(x^{(i)}, z^{(i)}; \theta)}{Q_i(z^{(i)})} \ \end{aligned}$&lt;/p&gt;
&lt;p&gt;由于log函数为凸函数，而我们想要求MLE的最大值，使用Jenson不等式，有&lt;/p&gt;
&lt;p&gt;$ \sum_{i} \log p(x^{(i)}; \theta) \geq \sum_{i}  \sum_{z^{(i)}}Q_i(z^{(i)} )log( \frac{p(x^{(i)}, z^{(i)}; \theta)}{Q_i(z^{(i)})}) $&lt;/p&gt;
&lt;p&gt;使用右侧的函数作为损失函数更加方便计算。&lt;/p&gt;
&lt;p&gt;对于  $Q_i(z)$  怎么取呢？我们希望对于  $\frac{p(x^{(i)}, z^{(i)}; \theta)}{Q_i(z^{(i)})}$  方便计算，最好为常数，那么就有&lt;/p&gt;
&lt;p&gt;$\frac{p(x^{(i)}, z^{(i)}; \theta)}{Q_i(z^{(i)})}$  ~c,结合  $\Sigma_zQ_i(z)=1$  有&lt;/p&gt;
&lt;p&gt;$\begin{align} Q_i(z^{(i)}) &amp;#x26;= \frac{p(x^{(i)}, z^{(i)}; \theta)}{\sum_z p(x^{(i)}, z; \theta)} \ &amp;#x26;= \frac{p(x^{(i)}, z^{(i)}; \theta)}{p(x^{(i)}; \theta)} \ &amp;#x26;= p(z^{(i)} | x^{(i)}; \theta) \end{align}$&lt;/p&gt;
&lt;p&gt;因此&lt;strong&gt;一般的EM algorithm的步骤&lt;/strong&gt; 为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;EM algorithm&lt;/p&gt;
&lt;h3&gt;Validate with Mixture of Gaussian&lt;/h3&gt;
&lt;p&gt;在Mixture of Gaussian 中，我们就是通过Bayes 公式去计算  $p(z^i|x,\phi)$  作为zi的分布，然后通过Jesnson不等式简化后的损失函数（同样是基于概率假设），使得对于每一个iteration之后，损失函数损失更小，参数更加接近真实值且反映出数据状况。（具体计算过程请见&lt;strong&gt;Problem Set 3 Solution&lt;/strong&gt; ）&lt;/p&gt;
&lt;h2&gt;Factor analysis&lt;/h2&gt;
&lt;p&gt;当数据维数大于数据的量时，由线性代数知识可知  $(x^1,x^2,...x^m)\in R^n$  这些向量全部是线性相关的，则对于Mixture of Gaussian时有&lt;/p&gt;
&lt;p&gt;$\Sigma_j = \sum_{i=1}^m w^i_j(x^{(i)} - \mu_j)(x^{(i)} - \mu_j)^T $  行列式的值为0，此时在计算Gaussian的概率分布时  $\frac{1}{|\Sigma|^{0.5}}=\frac{1}{0}$  这显然矛盾！这说明我们需要根据此时的数据特点做出些别的假设&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预处理：&lt;/strong&gt; 通过均值以及整体的方差将数据归一化&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心假设：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于标签  $z\in R^d$  表示认为标签为d类，同之前的总类数，有  $z$  ~  $N(0,I)$  (已经归一化了）&lt;/li&gt;
&lt;li&gt;数据与标签成线性关系  $x=\mu+\lambda z+\epsilon$  ,噪声  $\epsilon$  ~  $N(0,\Phi)$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;仍然是使用EM algorithm&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E step：&lt;/strong&gt; 计算  $P(z^i|x^i,\phi)$  ，由我们的假设，这是z和x的一个条件概率分布，也是正态分布，即有  $z^i|x^i,\mu,\lambda,\Phi$  ~  $N(\mu_{z^i|x^i},\Sigma_{z^i|x^i})$  ，我们通过协同概率去计算&lt;/p&gt;
&lt;p&gt;对于条件概率我们有&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;带入已知条件得到条件概率&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;M-step:&lt;/strong&gt; 这里仍然是暴力计算，得到结果为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;从而每个iteration迭代参数即可。对于Factor analysis可以将数据抽象成若干个特征，但是同时也可以反映不同特征的相关性，这点对于PCA是没有的。&lt;/p&gt;
&lt;p&gt;在cs229中我们简要的学习了几种的无监督学习的算法，无论是无概率还是有概率，都是一定的假设，包括特征值，距离，高斯假设，以及对于特征的分布的假设并由此可以进行分类，特征提取任务。但个人感觉最重要的还是对于&lt;strong&gt;信息量&lt;/strong&gt; 的问题。如果缺少了标签信息，就必须要一定的假设去补充，同样的，我们还可以添加一些别的假设，通过类似的方法，也可以得到新的无监督学习算法。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.c67k_r1q.jpg"/><enclosure url="/_astro/background.c67k_r1q.jpg"/></item><item><title>MIT 6.S184:扩散模型简介</title><link>https://bauklotze.vercel.app/blog/ai-learning-notes/mit-6s184-diffusion-models-intro/mit-6s184-diffusion-models-intro</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ai-learning-notes/mit-6s184-diffusion-models-intro/mit-6s184-diffusion-models-intro</guid><description>MIT 6.S184:扩散模型简介</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;生成式AI是目前的一个热点方向，类似于cs229中的无监督学习，都是通过训练数据集去学习到&lt;strong&gt;如何进行预测/生成结果&lt;/strong&gt;,只是对于无监督学习中目标(将数据进行合理的分类/提取)，评估方法都有较为简单的数学形式，而本文将会介绍对于生成式AI的生成原理，基本模型，训练目标，训练预测过程。&lt;/p&gt;
&lt;h2&gt;生成式AI的生成原理&lt;/h2&gt;
&lt;p&gt;Gnerative AI，输入一串指令y，我们希望基于指令生成一张图片，那么就会得到一个X, 而如果我们让他再生成一张，常常会生成一张不一样的。&lt;/p&gt;
&lt;p&gt;** 目标**：由于我们的每一次“希望AI生成一张图片”相当于一次查询取样，之际上就可以认为我们是从一个概率分布中去抽取一个样本，这提示我们Generative AI的目标是生成一个** 概率**。也就是对于所有的问题都要从概率论的角度去思考&lt;/p&gt;
&lt;p&gt;** 初始化**：实际上，如果我们进行任何的训练，就是一个啥都不会的模型，那么对于你输入任何的指令，它应该都只会输出一堆的噪声。即原始模型只会进行随机的输出&lt;/p&gt;
&lt;p&gt;** 数据集**：对于一张图片我们可以看成是由RGB三种颜色（3个通道的）大小为 $Height\times Weight$ 的矩阵，即为一张图片 $\in R^{C\times H\times W}$ ,对于视频就是加上时间的维度即为 $R^{T\times C\times H \times W}$ 。因此我们的输出为 ** $z\in R^d$ 的一个向量**。&lt;/p&gt;
&lt;p&gt;于是我们拥有的是 $(z_{sample},y_{sample})$ 的训练数据，用** 概率论**的思想，也是他们都是从我们希望的分布 $p_{data}(z,y)$&lt;/p&gt;
&lt;p&gt;中抽取的样本。&lt;/p&gt;
&lt;p&gt;因此对于生成式AI也就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过巨大的训练数据集作为&lt;strong&gt;随机抽样的样本&lt;/strong&gt; ，作为希望得到的概率分布 $p_{data}(z,y)$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练目标&lt;/strong&gt; ：将模型由初始的 $p_{init}$ ，通过训练得到一个&lt;strong&gt;变换关系&lt;/strong&gt; ，使得对于任何的y，都可以得到 $\hat{p}&lt;em&gt;{target}(x,y)$&lt;br&gt;
,而且希望&lt;strong&gt;通过某种评估手段&lt;/strong&gt; ，使得 $\hat{p}&lt;/em&gt;{target}(x,y)$ 与 $p_{data}(z,y)$ 在该意义下尽可能的接近。&lt;/li&gt;
&lt;li&gt;最后基于给的输入y，从 $\hat{p}_{data}(.|y)$ 中取样得到生成的数据，进而转换为图像形式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们对于 $p_{init}$ 而言，可以&lt;strong&gt;端到端&lt;/strong&gt; 的学习 $p_{data}$ ，但是在这门课程中，我们将会通过演化过程的角度，学习对于 $p_{init}$ 是如何经过演化关系变成 $p_{data}$ ,通过训练这个演化函数完成从 $p_{init}\Rightarrow p_{data}$ 的转变&lt;/p&gt;
&lt;h2&gt;演化的数学表达：微分方程&lt;/h2&gt;
&lt;p&gt;所谓的概率分布的“演化” ,就是对于其&lt;strong&gt;空间&lt;/strong&gt; 的一个变化，对于任意 $X_0\in R^d$ 根据某种演化关系 $X_t=f(X_0)$ ，直到 $X_t\in R^d$ ,如果 $X_0\sim p_{init}$ ,那么有 $X_t\sim p_{t}$&lt;/p&gt;
&lt;p&gt;因此我们最好的描述工具为&lt;strong&gt;微分方程&lt;/strong&gt;, 从简单考虑，使用一阶微分方程去进行描述，结合需要加上一定的随机性，我们使用** ODE(ordinary differential equations)&lt;strong&gt;以及&lt;/strong&gt; SDE(stochastic differential equations)**去描述&lt;/p&gt;
&lt;h3&gt;ODE以及Flow Models&lt;/h3&gt;
&lt;p&gt;** ODE**以 $R^d$ 空间上的任意一个点t=0时刻位置在 $X_0$ 的东西，对于t时刻他的位置为 $\phi_t(X_0)$ ，则有初始条件 $\phi_0(X_0)=x_0$ ,对于时间我们考虑 $t\in [0,1]$ 的范围&lt;/p&gt;
&lt;p&gt;假设在t时刻物体的“速度”为 $u_t(\phi(X_0))$ ,即为 $u: \mathbb{R}^d \times [0,1] \to \mathbb{R}^d, \quad (x,t) \mapsto u_t(x),$ ,则我们物体的“位移” X应该满足&lt;/p&gt;
&lt;p&gt;$\dfrac{\mathrm{d}}{\mathrm{d}t} \phi_t(X_0) = u_t(\phi_t(X_0))$ ** flow ODE**&lt;/p&gt;
&lt;p&gt;$\phi_0(X_0)=X_0$ ** flow initial conditions**&lt;/p&gt;
&lt;p&gt;** Flow Models**&lt;/p&gt;
&lt;p&gt;对于 $\phi$ 这个函数就表示了空间的流动情况，而如果我们对于考察的对象是从一个分布 $X_0\sim p_{init}$ ，那么对于 $\phi_t(X_0)$ 也应符合某个分布。特别的，我们希望在t=1(终点)的时候 $\phi_1(X_0)\sim p_{data}$ ,则有我们的Flow Models:（简单起见，记 $\phi_t(X_0)$ 为  $X_t $  )&lt;/p&gt;
&lt;p&gt;$\dfrac{\mathrm{d}}{\mathrm{d}t} X_t = u_t^{\theta}(X_t)$&lt;/p&gt;
&lt;p&gt;$X_0\sim p_{init}$&lt;/p&gt;
&lt;p&gt;我们通过训练神经网络 $u_t^{\theta}$ 希望在t=1时刻有 $X_1\sim p_{data}$ ，这个模型就叫flow models&lt;/p&gt;
&lt;p&gt;** 模拟Flow Models过程**&lt;/p&gt;
&lt;p&gt;由于flow models是一个分布到分布的变化，我们模拟的方法是** 多次从 $p_{init}$ 中取样并使用ODE进行模拟**&lt;/p&gt;
&lt;p&gt;而我们的ODE中的时间是连续的，为了模拟这个过程，我们使用** Euler Method**来模拟:将[0,1]划分为h大小的时间段，对于这段时间内用 $\dfrac{X_{t+h}-X_t}{h}$ 作为 $\dfrac{d}{dt}X_t$&lt;/p&gt;
&lt;p&gt;伪代码即为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## sampling from a flow model with Euler method
step1: set t=0, h=1/n
step2: draw a sample X0~pinit
for i =1,...n-1:
    X[t+h]=X[t]+h*ut(Xt)
    t:=t+h
return X1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;总结即为使用&lt;strong&gt;取样作为分布观察分布变化情况&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;SDE &amp;#x26; Diffusion Models&lt;/h2&gt;
&lt;p&gt;在ODE中我们是使用一个 $\dfrac{\mathrm{d}}{\mathrm{d}t} X_t = u_t^{\theta}(X_t)$ 作为更新函数，但是如果对于 $u_t^\theta，X_0$ 确定了，那么所有的位置都确定了。但是即便如此，我们任然希望能加上一点的不确定性，简单起见，我们考虑** 布朗运动**&lt;/p&gt;
&lt;p&gt;** 布朗运动(连续形式的markov过程)**&lt;/p&gt;
&lt;p&gt;对于一个布朗过程 $W=(W_t)_{0\leq t\leq 1}$ 是一个随机过程，满足 $W_0=0$ 且满足&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;独立增量&lt;/strong&gt; ：对于任意的 $0\leq t_0\leq t_1 ...\leq t_n=1$ ,增量 $W_{t_1}-W_{t_0},...W_{t_n}-W_{t_{n-1}}$ 为相互独立的随机变量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正态增量&lt;/strong&gt; ：对于任何的 $0\leq s \leq t \leq 1$ ,有 $W_t - W_s \sim \mathcal{N}(0, (t-s)I_d)$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即为任意小的时间段内，位置的变化都可以认为是一个正态分布。&lt;/p&gt;
&lt;p&gt;想要模拟布朗运动，我们仍然可以将[0,1]划分成n个长h的区间，只是由于正态增量原则，我们对于一个区间内的增量为 $\sqrt{h}*\mathcal{N}(0, I_d)$ ,即为&lt;/p&gt;
&lt;p&gt;$W_{t+h} = W_t + \sqrt{h}, \epsilon_t,\quad \epsilon_t \sim \mathcal{N}(0, I_d) \quad (t = 0, h, 2h, \ldots, 1 - h) \tag{5}$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDE&amp;#x26;Diffusion Models&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所谓的SDE,就是在ODE的每一步上加上由布朗运动产生的贡献&lt;/p&gt;
&lt;p&gt;$\begin{aligned} X_{t+h} &amp;#x26;= X_t + \underbrace{h u_t(X_t)}&lt;em&gt;{\text{deterministic}} + \sigma_t \underbrace{(W&lt;/em&gt;{t+h} - W_t)}&lt;em&gt;{\text{stochastic}} + \underbrace{h R_t(h)}&lt;/em&gt;{\text{error term}}\&amp;#x26;=X_t+hu_t(X_t)+\sigma_t \sqrt{h}\epsilon_t,\epsilon_t\sim \mathcal{N}(0, I_d) \end{aligned}$&lt;/p&gt;
&lt;p&gt;写成方程的形式即为 $\mathrm{d}X_t = u_t(X_t),\mathrm{d}t + \sigma_t,\mathrm{d}W_t$ ，如果我们的 $X_0\sim p_{init}$ 那么就称之为** Diffusion model**&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## sampling from a diffusion model using Euler-Maruyama method
step1: set t=0, h=1/n
step2: draw a sample X0~pinit
for i =1,...n-1:
    draw a sample \epsilon ~ N(0,Id)
    X[t+h]=X[t]+h*ut(Xt)+sigma[t]\sqrt{h}\epsilon
    t:=t+h
return X1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用SDE/ODE作为数学基础，通过训练 $u_t^{\theta}$ 来拟合分布的演化 $p_{init}\Rightarrow p_{data}$ 是我们的目标&lt;/p&gt;
&lt;h2&gt;建立训练的目标&lt;/h2&gt;
&lt;p&gt;通过第二部分，我们已经知道Flow Model $\dfrac{\mathrm{d}}{\mathrm{d}t} X_t = u_t^{\theta}(X_t)$ 以及Diffusion Model ,而接下来就是如何进行训练的问题.&lt;/p&gt;
&lt;p&gt;由于我们有的东西是数据集，即有大量的 $x$ 样本，自然的，而 $u_t^\theta(x)$ 为会给出一个输出，自然我们运用&lt;strong&gt;Supervised Learning&lt;/strong&gt; 的想法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;希望造出一些标签数据&lt;/strong&gt;,从而将损失函数定义为 $\mathcal{L}(\theta,x,t) = \Sigma^m_{i=1}| u_t^\theta(x_i) - u_t^{\text{target}}(x_i) |^2$ 就可以使用梯度下降了。&lt;/p&gt;
&lt;p&gt;于是我们的目标就变成了** 寻找一个对于training target的等式 $u_t^{target}$ .**&lt;/p&gt;
&lt;h3&gt;演化路径&lt;/h3&gt;
&lt;p&gt;我们建立该等式的中心思想是：为了寻找 $u_t^\theta(x)$ ,我们使用全概率公式的想法，学习来自不同的 $z\sim p_{data}$ 的结果 $u_t(x|z)$ ，最后合并到 $u_t(x)$ 上，从而我们需要考虑将考察对象 $p_t(X)$ ,以及”演化路径”也进行类似的转换&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;条件演化路径&lt;/strong&gt; ：对于任何的 $z\in R^d$ ,我们的有 $p_0(\cdot \mid z) = p_{\text{init}}, \quad p_1(\cdot \mid z) = \delta_z$ 那么称从 $p_0(|z)\Rightarrow p_1(|z)$&lt;br&gt;
的路径为条件演化路径(conditional probability path)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边缘演化路径&lt;/strong&gt; ：也就是对于 $p_{data}(z)$ 上进行积分 $z \sim p_{\text{data}}, \quad x \sim p_t(\cdot \mid z)  \Rightarrow  x \sim p_t ,\quad   p_t(x) = \int p_t(x \mid z) p_{\text{data}}(z), dz$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于这两者我的形象化的理解是：条件演化路径中 $p_t(.|z)$ 可以认为是 $t=0,h,.....1$ 可以认为是一个总线结构,其内部构成为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将 $p_0(x)$ 随着z打散到 $p_0(x|z)$ （类似于广播机制）&lt;/li&gt;
&lt;li&gt;然后通过某种操作对于 $p_t(x|z)$ 不断进行更新，使得我们的结果更加靠近 $p_1(x|z)$&lt;/li&gt;
&lt;li&gt;最后得到对于每一个 $p_1(.|z)$ 的一个权重&lt;/li&gt;
&lt;li&gt;如果我们需要计算 $p_t(X)$ ,那么将 $p_{data}(z)$ 看成是一个mask层，对于此时的 $p_t(x|z)$ 通过mask层最后得到 $p_t(x)$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;网络图形可以看成是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以发现，对于边缘演化路径而言，当 $z\sim p_{data}$ 的时候，有 $p_t(x)=\int_z\delta_z p_{data}(z)dz=p_{data}(z)$&lt;/p&gt;
&lt;p&gt;由于我们的 $p_{init}$ 一般为&lt;strong&gt;噪声数据&lt;/strong&gt; 高斯分布 $\mathcal{N} (0,I_d)$ ,对于我们想要变换到的z的空间上的每一个点，以一个类似于**”光锥“** 的东西将 $p_{init}$ 映射到这个点上，最后再做一个掩码层，就可以将取自 $p_{data}$ 的各种离散的数据z转换成可以用概率表示 $p_t(x)$ 中&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;条件速度以及边缘速度&lt;/h3&gt;
&lt;p&gt;原文中是使用向量场去描述，但是我觉得使用&lt;strong&gt;速度场&lt;/strong&gt; 更加的形象。&lt;/p&gt;
&lt;p&gt;由于我们一般而言是定义了从 $p_t(x|z)$ 的形式，可以理解为&lt;strong&gt;总线上的一根支线，最后使用掩码去合&lt;/strong&gt; 成，因此对于求解这个速度形式的话，也可以使用这种方法。&lt;/p&gt;
&lt;p&gt;如果我们可以求解出来 $u_t^{target}(X_t|z)$ 的话，就是需要知道如何将其合成起来即可。&lt;/p&gt;
&lt;h3&gt;1.从 $p_t(x|z)$ 到 $u_t^{target}(X_t|z)$&lt;/h3&gt;
&lt;p&gt;由于我们有 $\dfrac{d}{dt}X_t=u_t(X_t|z)$ ,则将 $X_t=p_t(x|z)$ 带进去即为 $\dfrac{d}{dt}p_t(x|z)=u_t(p_t(x|z))$ ,从而解微分方程即可&lt;/p&gt;
&lt;h3&gt;2.从 $u_t^{target}(X_t|z)$ 到 $u_t^{target}(X_t)$&lt;/h3&gt;
&lt;p&gt;对于这个可以通过如下定理内容实现&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定理1：&lt;/strong&gt; 对于 $z\in R^d$ ,使用 $u_t^{target}(.|z)$ 表示一个条件速度场，如果对于从 $X_0\sim p_{init} \Rightarrow X_t\sim p_t(.|z)$ 可以使用 $\dfrac{d}{dt}X_t=u_t^{target}(.|z)$ 去描述，则有 $u_t^{\text{target}}(x) = \int u_t^{\text{target}}(x|z) \frac{p_t(x|z)p_{\text{data}}(z)}{p_t(x)} ,\mathrm{d}z$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以使得 $X_0\sim p_{init} \Rightarrow X_t\sim p_t(x)$ 对应的速度场为 $\dfrac{d}{dt}X_t=u_t^{target}(X_t)$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定理2&lt;/strong&gt; ：对于 $z\in R^d$ ,使用 $u_t^{target}(.|z)$ 表示一个条件速度场，如果对于从 $X_0\sim p_{init} \Rightarrow X_t\sim p_t(.|z)$ 可以使用 $dX_t=u_t^{target}(X_t|z)dt+\sigma_t dW_t$ 去描述,则有，其中 $\nabla \log p_t(X_t)$ 是&lt;strong&gt;边缘得分函数&lt;/strong&gt; ， $\nabla \log p_t(x) = \int \nabla \log p_t(x|z) \frac{p_t(x|z) p_{\text{data}}(z)}{p_t(x)} ,\mathrm{d}z$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;证明：&lt;/strong&gt; 可以发现定理1实际上是定理2的在 $\sigma_t=0$ 的特殊形式&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;引理(Fokker-Planck Equation):&lt;/strong&gt; 对于一个随机过程 $X_t=p_t(x)$ ,它满足 $dX_t=u_t(X_t)dt+\sigma_tdW_t$ 等价于满足 $\partial_t p_t(x) = -\mathrm{div}(p_t u_t)(x) + \frac{\sigma_t^2}{2} \Delta p_t(x) \quad \text{for all } x \in \mathbb{R}^d, 0 \leq t \leq 1.$&lt;/p&gt;
&lt;p&gt;(引理的证明见附录)&lt;/p&gt;
&lt;p&gt;对于定理1，则有&lt;/p&gt;
&lt;p&gt;$\begin{align*} \partial_t p_t(x)  &amp;#x26;{=} \partial_t \int p_t(x|z) p_{\text{data}}(z) ,\mathrm{d}z \ &amp;#x26;= \int \partial_t p_t(x|z) p_{\text{data}}(z) ,\mathrm{d}z \ &amp;#x26;{=} \int -\mathrm{div}\big(p_t(\cdot|z) u_t^{\text{target}}(\cdot|z)\big)(x) p_{\text{data}}(z) ,\mathrm{d}z \ &amp;#x26;{=} -\mathrm{div}\left( \int p_t(x|z) u_t^{\text{target}}(x|z) p_{\text{data}}(z) ,\mathrm{d}z \right) \ &amp;#x26;{=} -\mathrm{div}\left( p_t(x) \int u_t^{\text{target}}(x|z) \frac{p_t(x|z) p_{\text{data}}(z)}{p_t(x)} ,\mathrm{d}z \right)(x) \ &amp;#x26;{=} -\mathrm{div}\big(p_t u_t^{\text{target}}\big)(x), \end{align*}$&lt;/p&gt;
&lt;p&gt;定理2则为&lt;/p&gt;
&lt;p&gt;$\begin{aligned} \partial_t p_t(x)  &amp;#x26;{=} -\operatorname{div}(p_t u_t^{\text{target}})(x) \ &amp;#x26;{=} -\operatorname{div}(p_t u_t^{\text{target}})(x) - \frac{\sigma_t^2}{2} \Delta p_t(x) + \frac{\sigma_t^2}{2} \Delta p_t(x) \ &amp;#x26;{=} -\operatorname{div}(p_t u_t^{\text{target}})(x) - \operatorname{div}\left( \frac{\sigma_t^2}{2} \nabla p_t \right)(x) + \frac{\sigma_t^2}{2} \Delta p_t(x) \ &amp;#x26;{=} -\operatorname{div}(p_t u_t^{\text{target}})(x) - \operatorname{div}\left( p_t \left[ \frac{\sigma_t^2}{2} \nabla \log p_t \right] \right)(x) + \frac{\sigma_t^2}{2} \Delta p_t(x) \ &amp;#x26;{=} -\operatorname{div}\left( p_t \left[ u_t^{\text{target}} + \frac{\sigma_t^2}{2} \nabla \log p_t \right] \right)(x) + \frac{\sigma_t^2}{2} \Delta p_t(x), \end{aligned}$&lt;/p&gt;
&lt;p&gt;有了这个定理，我们就可以将 $u_t^{target}(x|z)$ 转换成 $u_t^{target}(x)$&lt;/p&gt;
&lt;h2&gt;损失函数&lt;/h2&gt;
&lt;p&gt;我们已经知道对于我们的模型的初始假设：更新时 $p_t(x|z)$ 是如何从 $p_{init}$ 到 $\delta_z$ 的，衡量标准 $u_t^{target}$ ，以及如何进行预测以及更新（执行ODE），现在需要做的就是寻找一个&lt;strong&gt;合适的损失函数&lt;/strong&gt; 。&lt;/p&gt;
&lt;h2&gt;Flow Matching&lt;/h2&gt;
&lt;p&gt;对于flow model而言，我们的条件是 $X_0 \sim p_{\text{init}}, \quad \mathrm{d}X_t = u_t^\theta(X_t), \mathrm{d}t.$&lt;/p&gt;
&lt;p&gt;而我们希望有 $u_t^\theta \approx u_t^{target}$ ,那么自然而然的，想要使用对于&lt;strong&gt;速度场&lt;/strong&gt; 的L2损失&lt;/p&gt;
&lt;p&gt;$\mathcal{L}&lt;em&gt;{\mathrm{FM}}(\theta) = \mathbb{E}&lt;/em&gt;{t \sim \mathrm{Unif}, x \sim p_t} \bigl[ | u_t^\theta(x) - u_t^{\mathrm{target}}(x) |^2 \bigr] \ = \mathbb{E}&lt;em&gt;{t \sim \mathrm{Unif}, z \sim p&lt;/em&gt;{\mathrm{data}}, x \sim p_t(\cdot \mid z)} \bigl[ | u_t^\theta(x) - u_t^{\mathrm{target}}(x) |^2 \bigr]$&lt;/p&gt;
&lt;p&gt;但是这样的损失函数不是特别容易计算，特别是对于 $u_t^{\text{target}}(x) = \int u_t^{\text{target}}(x|z) \frac{p_t(x|z)p_{\text{data}}(z)}{p_t(x)} ,\mathrm{d}z$ 这个东西，这里的积分由于z是个连续的东西，因此不容易计算。相应的，我们应该仍然考虑通过容易获得的 $u_t^{target}(x|z)$ 去计算我们的损失函数。于是我们定义&lt;/p&gt;
&lt;p&gt;$L_{CFM}(\theta)=\mathbb{E}&lt;em&gt;{t \sim \mathrm{Unif}, z \sim p&lt;/em&gt;{\mathrm{data}}, x \sim p_t(\cdot \mid z)} \bigl[ | u_t^\theta(x) - u_t^{\mathrm{target}}(x|z) |^2 \bigr]$ 但是我们由下述定理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;定理3（条件损失等价于边缘损失）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;$L_{FM}(\theta)=L_{CFM}(\theta)+C$ ,其中C为与参数无关的常数，即有 $\nabla_{\theta}L_{FM}(\theta)=\nabla_{\theta}L_{CFM}(\theta)$ ,这说明了两种损失是等价的&lt;/p&gt;
&lt;p&gt;** Proof:**&lt;/p&gt;
&lt;p&gt;$\begin{aligned} \mathcal{L}&lt;em&gt;{\text{FM}}(\theta)  &amp;#x26;= \mathbb{E}&lt;/em&gt;{\tau \sim \text{Unif},, x \sim p_\epsilon} \left[ | u_t^\theta(x) - u_t^{\text{target}}(x) |^2 \right] \ &amp;#x26;= \mathbb{E}&lt;em&gt;{\tau \sim \text{Unif},, x \sim p&lt;/em&gt;\epsilon} \left[ | u_t^\theta(x) |^2 - 2, u_t^\theta(x)^T u_t^{\text{target}}(x) + | u_t^{\text{target}}(x) |^2 \right] \ &amp;#x26;= \mathbb{E}&lt;em&gt;{\tau \sim \text{Unif},, x \sim p&lt;/em&gt;\epsilon} \left[ | u_t^\theta(x) |^2 \right] 2\underbrace{\mathbb{E}&lt;em&gt;{\tau \sim \text{Unif},, x \sim p&lt;/em&gt;\epsilon} \left[ u_t^\theta(x)^T u_t^{\text{target}}(x) \right]}&lt;em&gt;{\substack{= \displaystyle \int_0^1 \int_x p&lt;/em&gt;\epsilon(x), u_t^\theta(x)^T u_t^{\text{target}}(x), dx, d\tau \ = \displaystyle \int_0^1 \int_z \int_x u_t^{\text{target}}(x|z), p_\epsilon(x|z), p_{\text{data}}(z), dx, dz, d\tau \ = \displaystyle \mathbb{E}&lt;em&gt;{\tau \sim \text{Unif},, z \sim p&lt;/em&gt;{\text{data}},, x \sim p_\epsilon(\cdot|z)} \left[ u_t^\theta(x)^T u_t^{\text{target}}(x|z) \right]}}-C_1 \ &amp;#x26;= \mathbb{E}&lt;em&gt;{\tau \sim \text{Unif},, z \sim p&lt;/em&gt;{\text{data}},, x \sim p_\epsilon(\cdot|z)} \left[ | u_t^\theta(x) |^2 - 2, u_t^\theta(x)^T u_t^{\text{target}}(x|z) + | u_t^{\text{target}}(x|z) |^2 - | u_t^{\text{target}}(x|z) |^2 \right] + C_1 \ &amp;#x26;= \mathcal{L}_{\text{CFM}}(\theta) + C_2 + C_1, \end{aligned}$&lt;/p&gt;
&lt;p&gt;因此原本使用 $L_{FM}(\theta)$ 实际上只需要使用 $L_{CFM}(\theta)$ 就可以了&lt;/p&gt;
&lt;p&gt;从而对于Flow matching的训练过程即为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Step 1: initialize with a dataset z~pdata
Step 2:
    for each mini-batch of data:
        sample z from dataset
        sample t from [0,1]
        sample epsilon~N(0,Id)
        sample x~pt(x|z)
        Loss=|u(x)-utargert(x|z)|2
        update the parameters
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Score Matching&lt;/h2&gt;
&lt;p&gt;对于diffusion model而言，我们是通过 $\mathrm{d}X_t = \left[ u_t^{\text{target}}(X_t) + \frac{\sigma_t^2}{2} \nabla \log p_t(X_t) \right] \mathrm{d}t + \sigma_t ,\mathrm{d}W_t$ 来更新函数的，但是同样的道理，我们无法直接去计算 $\nabla \log p_t(X_t) $ ,但是我们可以通过一个** score network**得到 $s_t^\theta(x)$ ,从而有 $\mathcal{L}&lt;em&gt;{\mathrm{SM}}(\theta)  = \mathbb{E}&lt;/em&gt;{t \sim \mathrm{Unif}, z \sim p_{\mathrm{data}}, x \sim p_t(\cdot \mid z)} \bigl[ | s_t^\theta(x) - \nabla \log p_t(x)|^2 \bigr]$&lt;/p&gt;
&lt;p&gt;类似于上面的讨论，我们可以用同样的定理以及推导方式发现我们只需要去计算&lt;/p&gt;
&lt;p&gt;$\mathcal{L}&lt;em&gt;{\mathrm{CSM}}(\theta)  = \mathbb{E}&lt;/em&gt;{t \sim \mathrm{Unif}, z \sim p_{\mathrm{data}}, x \sim p_t(\cdot \mid z)} \bigl[ | s_t^\theta(x) - \nabla \log p_t(x|z)|^2 \bigr]$&lt;/p&gt;
&lt;p&gt;即可&lt;/p&gt;
&lt;p&gt;综上所述，对于Score Matching的训练过程即为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Step 1: initialize with a dataset z~pdata
Step 2:
    for each mini-batch of data:
        sample z from dataset
        sample t from [0,1]
        sample epsilon~N(0,Id)
        sample x~pt(x|z)
        Loss=|s(x)-partial log p(x|z)|2
        update the parameter
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;给定指令下的图片生成&lt;/h2&gt;
&lt;p&gt;以上的部分我们使用的数据集默认没有指令,即为 $p_t^\theta(x|\phi)$ ,我们发现此时生成的图片随机性非常的大，不是我们想要的那些图片。我们需要添加一些的指示y，想要在 $p^\theta_t(x|y)$ 生成的图片，我们称有指令的generative model为guided generative model.&lt;/p&gt;
&lt;p&gt;** guided generative model:**我们的参数为&lt;/p&gt;
&lt;p&gt;$\begin{align*} \textbf{Neural network:} &amp;#x26; \quad u^\theta : \mathbb{R}^d \times \mathcal{Y} \times [0,1] \to \mathbb{R}^d, ; (x, y, t) \mapsto u_t^\theta(x|y) \ \textbf{Fixed:} &amp;#x26; \quad \sigma_t : [0,1] \to (0,\infty), ; t \mapsto \sigma_t \end{align*}$&lt;/p&gt;
&lt;p&gt;而我们的模型为&lt;/p&gt;
&lt;p&gt;$\begin{align*} \textbf{Initialization:} &amp;#x26; \quad X_0 \sim p_{\text{init}} \ \textbf{Simulation:} &amp;#x26; \quad \mathrm{d}X_t = u^\theta_t(X_t|y),\mathrm{d}t + \sigma_t,\mathrm{d}W_t \ \textbf{Goal:} &amp;#x26; \quad X_1 \sim p_{\text{data}}(\cdot|y) \end{align*}$&lt;/p&gt;
&lt;p&gt;而我们需要加上指令，只需要在训练的时候将一个输出以及一条指令看成一个&lt;strong&gt;pair&lt;/strong&gt; ，他们是从 $(z,y)\sim p_{data}(z,y)$ 中选取的，从而有损失函数变成了 $\mathcal{L}&lt;em&gt;{\text{CFM}}^{\text{guided}}(\theta) = \mathbb{E}&lt;/em&gt;{(z,y)\sim p_{\text{data}}(z,y),, t\sim\text{Unif}[0,1),, x\sim p_t(\cdot\mid z)} |u_t^\theta(x\mid y) - u_t^{\text{target}}(x\mid z)|^2.$&lt;/p&gt;
&lt;p&gt;对于 $u_t^{target}(x|z)$ 是在y的条件下进行&lt;strong&gt;图片的提取&lt;/strong&gt; ，然后我们的网络会结合y的指令，想办法得到理论上应该在y的条件下产生的图片差不多的图片。从而可以得到我们的结果。&lt;/p&gt;
&lt;h3&gt;Classifier Free Guidance(CFG)&lt;/h3&gt;
&lt;p&gt;虽然如此，但是我们在实际的应用中发现，如果直接使用这个网络去实现的话，效果不是特别好。我们的策略是&lt;strong&gt;奖励通过y的指令的图片，惩罚那些没有通过y的指令的图片&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;具体的过程为&lt;/p&gt;
&lt;p&gt;$\begin{align*} u_t^{\text{target}}(x|y) &amp;#x26;= a_t x + b_t \nabla \log p_t(x|y), \ &amp;#x26;= a_t x + b_t (\nabla \log p_t(x) + \nabla \log p_t(y|x)) = u_t^{\text{target}}(x) + b_t \nabla \log p_t(x|y). \end{align*}$&lt;/p&gt;
&lt;p&gt;从而对于右侧的一项&lt;strong&gt;添加一个guidance scale&lt;/strong&gt; ，有 $\tilde{u}_t(x|y) = u_t^{\text{target}}(x) + w b_t \nabla \log p_t(y|x)$&lt;/p&gt;
&lt;p&gt;这一个权重的原因是因为我们知道 $\nabla log p_t(y|x)$ 表示对于noised data的排除（因为我们的pt会比较的平均，导致整体的变化值不大，导致梯度不大)&lt;/p&gt;
&lt;p&gt;于是我们的w就是让模型知道这个&lt;strong&gt;对于y指令非常重要&lt;/strong&gt; ，需要添加一个权重，此时我们再带回去，即有&lt;/p&gt;
&lt;p&gt;$\begin{align*} \tilde{u}_t(x|y)  &amp;#x26;= u_t^{\text{target}}(x) + w_b t \nabla \log p_t(y|x) \ &amp;#x26;= u_t^{\text{target}}(x) + w_b t (\nabla \log p_t(x|y) - \nabla \log p_t(x)) \ &amp;#x26;= u_t^{\text{target}}(x) - (w_a t x + w_b t \nabla \log p_t(x)) + (w_a t x + w_b t \nabla \log p_t(x|y)) \ &amp;#x26;= (1 - w) u_t^{\text{target}}(x) + w u_t^{\text{target}}(x|y). \end{align*}$&lt;/p&gt;
&lt;p&gt;此时对于Flow Model而言，在预测的时候，使用 $dX_t=\tilde{u_t}^\theta(X_t|y)dt$ 去预测，同样的道理，对于Diffusion Model而言，我们也有 $\tilde{s}_t^\theta(x|y) = (1 - w) s_t^\theta(x|\varnothing) + w s_t^\theta(x|y)$ ，预测的时候，使用 $\mathrm{d}X_t = \left[ \tilde{u}_t^\theta(X_t|y) + \frac{\sigma_t^2}{2} \tilde{s}_t^\theta(X_t|y) \right] \mathrm{d}t + \sigma_t \mathrm{d}W_t$ 预测&lt;/p&gt;
&lt;h2&gt;Example: Gaussian probability path&lt;/h2&gt;
&lt;p&gt;由于我们能想到的最简单的分布&lt;strong&gt;就是高斯分布&lt;/strong&gt; ，高斯分布作为 $p_t(x|z)$ 的假设部分便显得非常的自然。接下来我们将会以 $p_t(x|z)=\mathcal{N}(\alpha_t z,\beta^2_t I_d)$ 为假设，推导出 $u_t^{target}(x|z),\nabla log p_t(x|z)$ 的具体形式，来实践以下以上的整个训练&amp;#x26;预测的流程&lt;/p&gt;
&lt;p&gt;由 $p_t(x|z)=\mathcal{N}(\alpha_t z,\beta^2_t I_d)$ ,我们可以得到 $x=\alpha_t z+\beta_t \epsilon,\epsilon\in N(0,I_d)$ (obvious)&lt;/p&gt;
&lt;p&gt;带入ODE中&lt;/p&gt;
&lt;p&gt;$\begin{aligned} &amp;#x26; \boxed{\alpha_t z + \beta_t x} = u_t^{\text{target}}(\alpha_t z + \beta_t x \mid z) \quad \text{for all } x, z \in \mathbb{R}^d \ &amp;#x26; \iff \alpha_t z + \beta_t \left( \frac{x - \alpha_t z}{\beta_t} \right) = u_t^{\text{target}}(x \mid z) \quad \text{for all } x, z \in \mathbb{R}^d \ &amp;#x26; \iff \left( \alpha_t - \frac{\beta_t}{\beta_t} \alpha_t \right) z + \frac{\beta_t}{\beta_t} x = u_t^{\text{target}}(x \mid z) \quad \text{for all } x, z \in \mathbb{R}^d \end{aligned}$&lt;/p&gt;
&lt;p&gt;带入道 $\nabla log p_t(x|z)$ 中，有 $\nabla \log p_t(x \mid z) = \nabla \log \mathcal{N}(x; \alpha_t z, \beta_t^2 I_d) = -\frac{x - \alpha_t z}{\beta_t^2}$&lt;/p&gt;
&lt;p&gt;这些即为我们的target的来源，在训练以及预测的时候直接带入即可。&lt;/p&gt;
&lt;h3&gt;$u_t^\theta(x)$ 的网络结构&lt;/h3&gt;
&lt;p&gt;早期的diffusion Model借鉴了&lt;strong&gt;U-Nets&lt;/strong&gt; 的结构Encoder,decoder,midcoder的结构，通过多层的Encoder+CNN+Resets的结构，再通过一个比较小的midcoder，最后以和Encoder同样大小的Decoder把信息进行输出。&lt;/p&gt;
&lt;p&gt;而在更加现代化的Diffusion Model中，我们常常使用一些特别的&lt;strong&gt;注意力机制&lt;/strong&gt; 去实现这些功能（具体的以我目前的水平还无法特别好的去理解，之后学完cs224n之后应该可以来完善这一块的内容）&lt;/p&gt;
&lt;p&gt;而在为了将我们的指令变成便于计算机理解的“y”，对于主流的模型&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;stable diffusion:&lt;/strong&gt; clip&amp;#x26;t5-xxl等embedding的方式，同时使用MM-DiT的方式&lt;/p&gt;
&lt;p&gt;** Meta Gen Video:**3 embeddings, cross&amp;#x26;self attention&lt;/p&gt;
&lt;p&gt;最后我们使用MNIST作为数据集，在google colab上使用T4跑了大概5min，得到一个可以生成数字的东西&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;以上就是对于flow&amp;#x26;diffusion model的Generative AI的简介，包括初始的假设，到我们的评判标准，到训练以及预测的过程，可以说是套着边缘分布，使用条件分布去实现的一个非常美丽的模型。&lt;/p&gt;
&lt;p&gt;但是对于 $u_t^\theta(x)$ 的结构，以及模型的各种假设还没有进行比较细致的讨论，更多的内容之后再UCB CS294-158以及&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//mit-6s978.github.io/%3Futm_source%3Dchatgpt.com&quot;&gt;MIT 6.S978&lt;/a&gt;去了解。&lt;/p&gt;
&lt;p&gt;最后感谢MIT提供的如此优秀的课程，感谢google colab提供的T4, 感谢所有的Mentor和TA做出来的这么美丽的课程，但是要是你们的作业的代码质量更高就好了(我的评价是史山)&lt;/p&gt;
&lt;p&gt;附：课程资料&lt;a href=&quot;https://link.zhihu.com/?target=https%3A//diffusion.csail.mit.edu/&quot;&gt;MIT 6.S184&lt;/a&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/titan2.ekMw1O7C.jpg"/><enclosure url="/_astro/titan2.ekMw1O7C.jpg"/></item><item><title>大一暑假ai学习计划</title><link>https://bauklotze.vercel.app/blog/reflections/freshman-summer-ai-learning-plan/freshman-summer-ai-learning-plan</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/freshman-summer-ai-learning-plan/freshman-summer-ai-learning-plan</guid><description>大一暑假ai学习计划</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;由于USTC对于少年班学院学生的特殊政策，我直到大一下的4月份才确定之后走ai方向，忙于数理基础和各种ddl的我，直到7月份才有学了半本的dive intodeep learning，且Python等编程基础比较薄弱。&lt;/p&gt;
&lt;p&gt;因此这个暑假的基本任务是完成实验室基本论文的学习（交叉注意力)，以及人工智能理论以及代码能力的提高，为之后的科研工作做准备。&lt;/p&gt;
&lt;p&gt;准备学习：&lt;/p&gt;
&lt;p&gt;随机过程：这个学期在照顾苕皮必须的数理基础之后，选了一个概率论与数理统计。下个学期正好选上随机过程，把这一块给学习完成&lt;/p&gt;
&lt;p&gt;离散数学：cs数学基础课，准备找时间学习完成。&lt;/p&gt;
&lt;p&gt;cs229:学习机器学习的理论，本人之前只学过一部分的dl对于ml还不是很熟悉，顺便提高代码能力。&lt;/p&gt;
&lt;p&gt;cs230：个人之前学习李沐的d2l各种算法以及网络结构时候感觉这些东西就是从石头中蹦出来的，希望通过这门课来提高水平。&lt;/p&gt;
&lt;p&gt;如果还有时间的话会学习cs234(rl)，cs231n(cv)，cs224（nlp），最后学过这些东西之后再看往哪个领域深入研究。&lt;/p&gt;
&lt;p&gt;虽然这个暑假还有7天蔷薇访学和一些别的课，希望我可以在这个暑假把以上的东西给学完。快船总冠军！！！&lt;/p&gt;</content:encoded><h:img src="/_astro/background.DNzgYXZo.jpg"/><enclosure url="/_astro/background.DNzgYXZo.jpg"/></item><item><title>大一暑假ai学习总结</title><link>https://bauklotze.vercel.app/blog/reflections/freshman-summer-ai-learning-summary/freshman-summer-ai-learning-summary</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/freshman-summer-ai-learning-summary/freshman-summer-ai-learning-summary</guid><description>大一暑假ai学习总结</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这个暑假2个月基本上都呆在了学校里面，每天可以说是摆摆学学，学习计划中的内容基本完成了，但是也有一些做的不好的地方&lt;/p&gt;
&lt;h2&gt;学习总结&lt;/h2&gt;
&lt;h3&gt;AI课程完成情况：&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;cs229 Machine Learning:&lt;/strong&gt; 从头到尾的完成了所有内容的学习，包括Lecture, problem set并且已经将所有内容push到了github仓库中，欢迎大家点赞收藏。&lt;/p&gt;
&lt;p&gt;** cs230 Deep Learning:** 完成了主体的部分：coursera上的线上内容(videos+assignments)，而cs230的Lecture部分更多是观点以及方法论上的指导，下个学期再学啦！&lt;/p&gt;
&lt;p&gt;** MIT 6.S184 Generative AI Scratch**: 花了几天的时间干完了这门体量比较小的课程，lecture note写的非常的好（虽然没有学过随机过程的我有点吃力），重点是在于Diffusion model的建立以及实现过程，体验非常好的一门课程。&lt;/p&gt;
&lt;p&gt;别的数学课程：随机过程稍微的看了一点点，开摆了。所有课程只能下个学期跟着老师学了（翘不了课了，悲伤）&lt;/p&gt;
&lt;h3&gt;美中不足的地方&lt;/h3&gt;
&lt;p&gt;1.大致确定了之后会走NLP，Generative AI的方向。&lt;/p&gt;
&lt;p&gt;2.实验室的任务完成度为0%（我们需要更为强大的基础）, 觉得等实力足够之后再去联系吧&lt;/p&gt;
&lt;p&gt;3.GRE单词背诵量约等于0，下个学期在忙中还是需要抽出来一点点的时间学英语的。&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;cs229 的强化学习部分还没有整理（3篇知乎文章），cs230的CNN,RNN，tensorflow部分还没有整理(7篇文章)，MIT 6.S184的万字长文完成度为30%&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总体而言，这个暑假我对自己的学习情况还算满意，虽然知乎上的更新严重不足（整理成自己的语言实在是过于的耗费体力和时间了，一篇文章可能需要写个1.5h+）,但是还是学到了不少的知识。&lt;/p&gt;
&lt;h3&gt;下个学期的任务&lt;/h3&gt;
&lt;p&gt;** 准备学习**&lt;/p&gt;
&lt;p&gt;Stanford cs224n:自然语言处理的神课，不仅介绍了基本的RNN,Transformer等网络结构，更重要的是介绍了关于模型的pre-training,post training以及一些语言学的知识，需要立刻学习的一门课程&lt;/p&gt;
&lt;p&gt;Stanford CS336: 一门听说非常好的课程，会具体的教会我们实现一个大语言模型的各个部分，感觉到时候要破费租服务器了&lt;/p&gt;
&lt;p&gt;Stanford cs224W: 介绍图神经网络的一门课程，个人感觉使用图的观点去思考神经网络会非常的有趣。&lt;/p&gt;
&lt;p&gt;CMU 15-213:大名鼎鼎的csapp,非常硬核的一门课，个人希望可以更加具体的了解计算机的实现过程。&lt;/p&gt;
&lt;p&gt;计算机结构方向：先完成cs61c的学习，然后上手csapp的学习,有时间学习分布式系统的话学一下CMU15-418（理解计算机的底层结构，掌握像cuda之类的东西）&lt;/p&gt;
&lt;p&gt;数值分析 MIT 18.330：在MIT 6.S184的实现过程中，我深刻体会到了使用计算机去解决ODE&amp;#x26;SDE的美妙之处，非常希望可以通过这门课程加深自己对于计算科学的理解。&lt;/p&gt;
&lt;p&gt;如果还有时间的话会去更深入的学习LLM的内容，对于cv,rl之类的课程也会进行学习。毕竟所有的知识都是互通的，在经过了这个暑假的学习之后，我深刻的体会到了这一点。&lt;/p&gt;
&lt;p&gt;把这些东西给干完了之后个人感觉进组就能稍微的做一点事而不是搬砖了，希望可以把这些东西给学完，同时GPA可以提高到3.95+(万恶的中国近代史纲要毁我大一绩点)，最后还是希望自己可以能在能力范围之内为人类科学做出一点点的贡献。&lt;/p&gt;
&lt;p&gt;9.3更&lt;/p&gt;
&lt;p&gt;今天在学习cs224n的时候，看了看recommended reading中的论文，发现自己对于数据结构的理解还是太浅了，又担心我们USTC的神奇教学质量，遂决定在准备自学的名单上加上一门叫做UCB cs61B的课程。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.DNzgYXZo.jpg"/><enclosure url="/_astro/background.DNzgYXZo.jpg"/></item><item><title>工作流反思(1）</title><link>https://bauklotze.vercel.app/blog/reflections/workflow-reflection-1/workflow-reflection-1</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/reflections/workflow-reflection-1/workflow-reflection-1</guid><description>工作流反思(1）</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今天将&lt;strong&gt;东川路第一伊雷娜&lt;/strong&gt; 的反思文章认真拜读了一下，深有感触。感觉有的时候即使我进行了每日日程的记录，但是缺少对于工作流的反思，导致工作效率无法得到质的飞跃。&lt;/p&gt;
&lt;p&gt;我是从7月份开始系统性的学习ai的，从7月份到10月份，我完成了大概4门课程的系统性的学习，至少从学习速度上看不如伊雷娜，究其原因，可能还是&lt;strong&gt;学习时长和专注程度不够&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;仔细思考了一下学习cs229,230的工作流，大概为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每日的有效工作时长是8-9h，日程表为&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;大概9点开始学习，写一篇知乎学习文章+听课，学到11.45左右&lt;/li&gt;
&lt;li&gt;中午结束学习到下午开始学习共1.75h摆烂，但是&lt;strong&gt;实际上我只午睡10min!!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;下午从1.30到5.30学习，然后去打球&lt;/li&gt;
&lt;li&gt;打球1.5h，晚上大概7.45开始学习，直到闭馆10.45&lt;/li&gt;
&lt;li&gt;晚上1.30睡觉&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;对于&lt;strong&gt;学习日志总结，完成lab/hw,以及听lecture&lt;/strong&gt; 几个中间，可能时间分配为&lt;strong&gt;30%,30%,40%&lt;/strong&gt;,但是一般而言是等到堆了大概6h需要总结的内容时我再去总结&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于暑假和9月份的时间安排可以发现&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每日手机使用过长，每日4h+,尤其是xhs上&lt;/li&gt;
&lt;li&gt;对于知识总结不够及时，导致&lt;strong&gt;总结的时候需要花大量时间回顾&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;打球前后的时长过长(篮球太有趣了)，前后大概2h进去了&lt;/li&gt;
&lt;li&gt;饭前饭后的工作流需要简化&lt;/li&gt;
&lt;li&gt;补充一个最近发现的问题：&lt;strong&gt;找到的关键的论文需要及时阅读&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对以上问题，我决定&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;篮球时长&lt;/strong&gt; 不能少！！！打球时会和同学有海阔天空的交谈，能启发我的思路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​ 但是可以减少前后的时间，比如&lt;strong&gt;提早约球，减少等人时长&lt;/strong&gt; ，&lt;strong&gt;打完球立刻回宿舍洗漱，晚上略微少吃点&lt;/strong&gt;,这样可以做到大概在7.00前开始学习&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于&lt;strong&gt;工作流&lt;/strong&gt; 上，及时总结，将写一篇3000字知乎文章的时间压缩到&lt;strong&gt;大概2h以内&lt;/strong&gt; ，听完&lt;strong&gt;大概2lecture+1hw/lab&lt;/strong&gt; 之后立刻总结&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;论文问题的话保证&lt;strong&gt;每周至少读两篇论文，要写专业的总结报告&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于上文化课时，如果老师讲的暂时都会，那么就** 用电脑看slide+完成lab/hw**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生活作息上，尽量只有早上起来看一眼消息，中午回一下消息，晚上吃饭时看一眼，晚上回宿舍路上看一眼，别的时间最多&lt;strong&gt;听听歌&lt;/strong&gt; ，控制手机使用时长在2h以内&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;目标：&lt;/strong&gt; 每周完成大概6000字的知乎创作(2 article)+每日有效学习时长在11h以上&lt;/p&gt;
&lt;p&gt;关于娱乐&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;音乐&lt;/strong&gt; 是必不可少的，最近听的包括&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;四月是你的谎言，电磁炮，你的名字，丝之歌ost&lt;/li&gt;
&lt;li&gt;反复聆听：unravel, 声嘶力竭&lt;/li&gt;
&lt;li&gt;音单常客：Animenzzz合集，进击的巨人ost, 鬼灭之刃ost&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;nba&lt;/strong&gt; 可以康康，但是仅限于看一眼集锦和比分，数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;游戏&lt;/strong&gt; 的话，最多打打pvz95放松身心&lt;/li&gt;
&lt;li&gt;最近还开始学习&lt;strong&gt;唱日语歌&lt;/strong&gt; ，包括&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;call of silence, call your name&lt;/li&gt;
&lt;li&gt;unravel(正在学习)&lt;/li&gt;
&lt;li&gt;声嘶力竭，红莲华，红莲的弓矢，炎&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;娱乐也是非常重要的一部分，不用时刻保持自己处于高强度作息，减少低级的浪费时间的行为才是我应该做的&lt;/p&gt;
&lt;p&gt;最后附上一张圣巢一哥的小玩偶，以后它就待在我边上一起学习啦！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>计算机网络(1): 计算机网络简介&amp;应用层介绍(chap1,2)</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/computer-networks-1-introduction-application-layer/computer-networks-1-introduction-application-layer</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/computer-networks-1-introduction-application-layer/computer-networks-1-introduction-application-layer</guid><description>计算机网络(1): 计算机网络简介&amp;应用层介绍(chap1,2)</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;之前在实验室打螺丝的时候，就有在服务器上进行一堆的操作，而这个过程中，有好多常见的概念, 这些都是计算机网络这么课程所介绍的。而我们USTC的计算机网络个人感觉课程设置还是挺不错的(毕竟在csdiy中都有推荐)，教材使用的是大名鼎鼎的《&lt;strong&gt;计算机网络：自顶向下方法&lt;/strong&gt; 》，课程内容也基本是围绕这本书展开的。&lt;/p&gt;
&lt;p&gt;Chap1个人在学的时候感觉还是挺新奇的，作者通过物理结构&amp;#x26;逻辑结构介绍了整个计算机网络的框架，而Chap2则是从最顶端的“应用”去介绍端与端之间通信时所遵循的原则，以及一些特殊的文件传输方式&lt;/p&gt;
&lt;h2&gt;Chap1: 计算机网络简介&lt;/h2&gt;
&lt;h3&gt;计算机网络物理结构&lt;/h3&gt;
&lt;p&gt;** 端系统：** 网络中各种设备，像冰箱，彩电，空调，洗衣机,手机，服务器，计算机等都称为端系统&lt;/p&gt;
&lt;p&gt;** 分组交换机：** 进行传输数据的管理的机器，常见的有路由器，链路层交换机等&lt;/p&gt;
&lt;p&gt;** 通信链路：** 将各种设备连接起来的路径&lt;/p&gt;
&lt;p&gt;** ISP:** 全名为Internet Service Provider, 可以认为是一个“自治”的节点，对于ISP内部可以进行相互的连接，而ISP之间又有连接关系&lt;/p&gt;
&lt;p&gt;各种端设备通过通信链路，经过了大量的分组交换机(进行传输数据管理)，并形成大的ISP进行互联，这就是计算机网络的架构，而对于数据进行传输，需要按照响应的** 套接字接口进行连接** （类似于c中的参数传递），并且按照满足一定的** 协议** (类似于人类的语言)，这便是在计算机网络上通信的要求&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;计算机网络逻辑结构&lt;/h3&gt;
&lt;p&gt;类似于购买机票，我们需要购买(网络应用进行一些操作)，在机场进行转移以及手续办理(将操作变成可以传递的东西)，确定路线图(确定我们需要以什么路径进行传输)，开始飞行（正在运输），以及飞行的过程（怎么飞）。&lt;/p&gt;
&lt;p&gt;可以发现，** 模块化的设计** 可以大大的简化我们分析的流程，而对于每一个模块，只要知道如何“对接”以及通过那些接口进行传递，网络设计者以分层的结构设计的网络。每一层会遵守相应的协议。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;应用层&lt;/strong&gt; ：有大量的协议(HTTP,SMTP,FTP…)，我们可以根据协议设计不同的应用，产生需要传递的信息，并且以满足相应协议格式的报文进行传输&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运输层&lt;/strong&gt; ：常见协议有TCP/UDP,他们会将报文分割成报文段&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络层&lt;/strong&gt; ：通过运输层的报文段确定传输的路径，而确定路径中的每个端系统的位置的“identification”也会满足一定的协议，常见的有IP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链路层&lt;/strong&gt; ：确定我们对于传输的时候应该如何去传输&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理层&lt;/strong&gt; ：就是开始传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而我们在进行运输的时候，则会用从应用层=&gt;物理层，再从物理层=&gt;应用层，每一层满足上下级之间的接口，这就是我们的传输时的逻辑结构。&lt;/p&gt;
&lt;p&gt;以上为chap1的主体内容，而第一章还有一些零碎的内容（接入网，物理层介绍&amp;#x26;网络传输的模式）&lt;/p&gt;
&lt;p&gt;** 接入网** ：即为从端设备到边缘路由器的网络，这段网络常见有通过&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数字用户线&amp;#x26;电缆：分别借用电视线以及电话线进行传输&lt;/li&gt;
&lt;li&gt;光纤到户：使用光纤进行型号传递&lt;/li&gt;
&lt;li&gt;以太网接入技术：使用双绞铜线于一台交换机进行连接，WiFi&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;报文传输以及时延计算&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;对于一段长长的东西，传输时我们会将长长的报文划分成小的数据块，称之为分组进行传递，而对于每一个组的传输，多个组的传输方式，以及时延的计算&amp;#x26;可能出现的问题便是我们需要研究的对象&lt;/p&gt;
&lt;p&gt;** 单个分组的传输：**&lt;/p&gt;
&lt;p&gt;假设从源，经过一个分组交换机传输到目的地，假设分组大小L bit,而传输速率为R bit/s(bps)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先经过一个链路：源以R 的满bps将分组进行上传，总共时间为（L/R s)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储转发传输&lt;/strong&gt; ：分组交换机进行传递的时候，会在接收完整个分组，存储在交换机里面之后，再进行传输&lt;/li&gt;
&lt;li&gt;然后再经过一个链路（L/R s)，总共时间为2(L/R)s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样的，如果有(N-1)台路由器，那么一个分组的时延为N(L/R)s&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多个分组的传输：&lt;/strong&gt; 对于每一个分组到达一个分组交换机并且接收完毕之后，只有等到** 前面的分组传输完毕之后才能传输**,这个排队的过程会产生一定的时间延迟&lt;/p&gt;
&lt;p&gt;** 时延的分类**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;处理时延&lt;/strong&gt; ：分组交换机处理分组比特并且确定应该导向哪里的时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排队时延&lt;/strong&gt; ：分组等待传输所需要的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;若对于一个分组交换机，每秒到达a个分组，每个分组L bit，传输速率为R bps,则我们每秒有La bit的输入以及R bit的输出，我们记 $\eta=\dfrac{La}{R}$ 为流量强度，来衡量时间延迟，在考虑统计原理之后，我们发现** 当流量强度接近1的时候，平均排队延迟大大增加，直到正无穷**&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传输时延&lt;/strong&gt; ：将分组上传到链路上所需要的时间L/R&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传播时延&lt;/strong&gt; ：信号在链路上传输的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从而总的时间延迟为几个时间延迟全部加起来&lt;/p&gt;
&lt;h2&gt;Chap 2: 应用层介绍&lt;/h2&gt;
&lt;p&gt;chap1系统性的介绍了一下计算机网络，而chap2则是系统的介绍了一下应用层于运输层之间的接口以及常见网络应用的协议&lt;/p&gt;
&lt;h3&gt;应用层通信过程&lt;/h3&gt;
&lt;p&gt;** 服务器** ：一种特殊的端设备，常年开机，来处理来自于客户的请求&lt;/p&gt;
&lt;p&gt;** 网络应用体系结构** ：对于我们的信息的传递，常见的体系结构有应对web search之类的客户——服务器体系结构，它可以即时对于客户的要求进行相应，同时还有对于主机之间进行直接通信的P2P结构&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;** 通信接口** ：有了体系结构(图），对于图中的每个顶点以及边的连接处就是我们的** 通信接口** 。而我们的应用层进行通信时，会将发送请求的进程标志位客户，而请求的对象标识位服务器，他们之间更具运输层的TCP或UDP协议，确定对方的ip地址并且进行通信。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;我们知道了通信过程，而对于不同的应用有相应的协议，他们规定了应该发送什么东西以及什么时候发送，也就是对于不同应用之间交互时的** 语言** ，而接下来我们就** 即时相应，存储响应，ip查询以及文件分发** 几个比较常见的功能以及例子进行介绍。&lt;/p&gt;
&lt;h3&gt;即时相应:Web应用&lt;/h3&gt;
&lt;p&gt;网络应用就是即时相应的典型例子，一个web界面是由大量的** 传输对象** 构成的(HTML文本+若干个应用图片)。而从服务器获得一个网络应用，会遵从HTTP协议。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTTP协议&lt;/strong&gt; :规定了请求web页面以及接收的过程&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单个对象收发过程&lt;/strong&gt; ： $A向B请求建立连接(握手)\Rightarrow B给A连接成功/失败响应 \Rightarrow A请求发送对象 \Rightarrow B返回报文/引用的对象\Rightarrow 关闭tcp连接$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http1.0:非持续连接，总共有3次握手，每个对象传输要2个RTT,N个对象2N RTT&lt;/p&gt;
&lt;p&gt;http1.1⁄2:持续连接,对于建立连接之后全部传输&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;而我们的HTTP协议则规定了请求报文以及响应报文的格式以及传输的对象。&lt;/p&gt;
&lt;p&gt;web应用还有些别的细节，如使用cookie作为识别用户的表示，使用web缓存器来加快响应速度&lt;/p&gt;
&lt;h3&gt;存储响应：电子邮件&lt;/h3&gt;
&lt;p&gt;有的时候我们需要将文件进行上传并且存储，而别人也会对此进行访问，像电子邮件。电子邮件的上传遵从SMTP协议。&lt;/p&gt;
&lt;p&gt;而** 存储响应过程** ：A給B发电子邮件&lt;/p&gt;
&lt;p&gt;$A将邮件发到A的ISP的邮件服务器\Rightarrow A的服务器将邮件发到B的服务器上 \Rightarrow 存储在B的服务其上，供B查询$&lt;/p&gt;
&lt;h3&gt;IP查询：因特网目录功能&lt;/h3&gt;
&lt;p&gt;对于每一个主机我们想要定位到它，那么它必须有自己独特的标识(身份证号码），因此对于每一个主机的位置我们使用** IP地址** 进行标志(114.514.191.8这样的东西)，但是实际上每一个服务器都拥有&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//www.baidu.com&quot;&gt;http://www.baidu.com&lt;/a&gt;这样的方便记忆的** 域名** ，而将域名与IP地址进行对应查找就非常的重要，而这个查找工作就是DNS的工作&lt;/p&gt;
&lt;p&gt;** 分布式数据库** ：dns使用大量的dns服务器，而我们使用** 树的结构** 将dns服务器进行组织。对于每一个父亲dns服务器，都会包含其所有的儿子dns服务器的ip地址供查询。而儿子会知道其父亲的ip&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;查询的时候(以递归查询为例子)，假设我们主机为cse.nyu.edu,想要查询&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//cs.ustc.edu&quot;&gt;http://cs.ustc.edu&lt;/a&gt;的服务器的IP，那么我们会&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主机与本地dns服务器&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//dns.nyu.edu&quot;&gt;http://dns.nyu.edu&lt;/a&gt;握手建立练习，发送查询请求&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//dns.nyu.edu&quot;&gt;http://dns.nyu.edu&lt;/a&gt;向&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//nyu.edu&quot;&gt;http://nyu.edu&lt;/a&gt;发送查询请求&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//nyu.edu&quot;&gt;http://nyu.edu&lt;/a&gt;向.edu服务器发送请求&lt;/li&gt;
&lt;li&gt;…最后知道&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//cs.ustc.edu&quot;&gt;http://cs.ustc.edu&lt;/a&gt;收到请求，然后将自己的IP传给&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//ustc.edu&quot;&gt;http://ustc.edu&lt;/a&gt;这个东西&lt;/li&gt;
&lt;li&gt;…最后&lt;a href=&quot;https://link.zhihu.com/?target=http%3A//cs.ustc.edu&quot;&gt;http://cs.ustc.edu&lt;/a&gt;的IP传回给了本地的dns服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上是dns服务工作的流程，而我们也会有一些改进措施来减轻根服务器的压力，如建立&lt;strong&gt;dns数据库&lt;/strong&gt; 来存储常见的域名&amp;#x26;IP对应，以及** dns缓存** 来存储近期的常见的查询从而节省时间&lt;/p&gt;
&lt;h3&gt;文件分发：P2P结构&lt;/h3&gt;
&lt;p&gt;与客户-服务器结构相比，P2P的扩展性和响应速度都更快，对于小型的网络非常使用。&lt;/p&gt;
&lt;p&gt;** P2P结构** ：传统的客户-服务器结构中，对于客户A想要将文件分发给B,C,D需要上传一份到B,再上传一份给C,再上传一份给D,而P2P结构时对于A上传给了B之后，B与A一起进行上传并且给C，然后A,B,C一起使用上传能力给到D，即为** P2P结构充分利用了在这个网络中的所有成员的上传能力**&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;而对于文件分发的时候，我们使用BitTorrent 协议利用这种机制实现高效、可扩展的文件分发。&lt;/p&gt;
&lt;p&gt;以上便是chap1,chap2的主要内容，之后我们继续研究运输层等层次的相关协议以及工作流程。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BgtaMcCB.jpg"/><enclosure url="/_astro/background.BgtaMcCB.jpg"/></item><item><title>计算机网络(2): 运输层简介(UDP&amp;&amp;TCP)</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/computer-networks-2-transport-layer-udp-tcp/computer-networks-2-transport-layer-udp-tcp</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/computer-networks-2-transport-layer-udp-tcp/computer-networks-2-transport-layer-udp-tcp</guid><description>计算机网络(2): 运输层简介(UDP&amp;&amp;TCP)</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;应用层规定了对于不同类型的应用我们应该以什么方式存储什么样的报文，而&lt;strong&gt;运输层&lt;/strong&gt; 则是控制应该如何控制这些报文的传输的，要保证数据&lt;strong&gt;能在规定时间内，不发生错误的进行传输&lt;/strong&gt;,同时对于发生** 传输错误**问题的解决方案，就是运输层要解决的问题&lt;/p&gt;
&lt;p&gt;常见的运输层的协议有两个，UDP(不可靠，无连接的服务)以及TCP(可靠，面向连接)，他们的任务就是** 将分组以某种方式在不同的进程上进行传输**。&lt;/p&gt;
&lt;p&gt;而在讨论运输层本身之前，我们需要考虑运输层与** 上方应用层和下方网络层的接口**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用层接口：多路复用&lt;/li&gt;
&lt;li&gt;网络层接口：多路分解&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而我们对于UDP&amp;#x26;&amp;#x26;TCP的多路复用分解则是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UDP:只有目标端口号&lt;/li&gt;
&lt;li&gt;TCP:同时包含目标端口号和源端口号&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;UDP报文结构&lt;/h2&gt;
&lt;p&gt;UDP相比于TCP而言好处有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于那些发送什么数据，何时发送的应用层控制更加友好&lt;/li&gt;
&lt;li&gt;不用3次握手&lt;/li&gt;
&lt;li&gt;不需要连接&lt;/li&gt;
&lt;li&gt;分组简单，减少分组包的大小&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此我们的在线游戏，视频会议，网络管理之类的常常会使用UDP,但是像电子邮件之类的就不行&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UDP结构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检验机制&lt;/strong&gt; ：虽然UDP不保证可以完美的送达，但是&lt;strong&gt;判断收到的报文是否正确&lt;/strong&gt; 还是需要的，就比如在线游戏时你可能理论上你遇到了一个僵尸，这时候传输错误了，你不希望它变成一个末影龙是吧，因此UDP设计了一个最为简单的检验&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;检验和：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计算过程：将伪头部，UDP头部，数据拼接，首先将检验和设为0，如果总字节数为奇数，追加一个全0字节使得长度变成偶数，反码求和并且取反就是检验和&lt;/li&gt;
&lt;li&gt;验证过程:&lt;strong&gt;进行同样的计算过程，校验和字段初始为发送的值，如果传输没有出错，那么全为1&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UDP检验和是一种较为简单的错误检测机制&lt;/p&gt;
&lt;h2&gt;可靠数据传输原理&lt;/h2&gt;
&lt;h3&gt;Why 可靠数据传输&lt;/h3&gt;
&lt;p&gt;我们需要给** 应用层提供一条可靠的传输路径**，而网络层会给我们提供一条** 不可靠&lt;strong&gt;的传输路径，因此运输层就需要一个&lt;/strong&gt; 可靠数据传输协议**进行这个操作&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;目标:&lt;/strong&gt; 接受应用层的报文，并且发送到网络层&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;方式:&lt;/strong&gt; 通过一个协议，管理报文的传输&lt;strong&gt;顺序…&lt;/strong&gt; ，从而让数据进行可靠传输&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而可能出现的问题时&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接进行报文传输&lt;/li&gt;
&lt;li&gt;如果报文发生错误了怎么办&lt;/li&gt;
&lt;li&gt;如果报文发送丢失了怎么办&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来我们将会使用&lt;strong&gt;有限状态机&lt;/strong&gt; 描述&lt;strong&gt;接收方，发送方&lt;/strong&gt; 的协议操作&lt;/p&gt;
&lt;h3&gt;Rdt1.0：直接进行报文传输&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;发送端：从上层接收数据，封装成分组送入下层信道&lt;/li&gt;
&lt;li&gt;接收端：从下层信道接收分组，取出数据交给上层&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Rdt2.0：报文错误查验&lt;/h3&gt;
&lt;p&gt;非常朴素的想法:&lt;strong&gt;接收方直接喊话发送方&lt;/strong&gt; ，如果&lt;strong&gt;接收方发现传错了&lt;/strong&gt;,那么就要求发送方重新传一个&lt;/p&gt;
&lt;p&gt;因此恢复错误的方式就是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;肯定确认&amp;#x26;&amp;#x26;否定确认&lt;/strong&gt; (ACK/NAK):接收方告诉发送方你发对了没有&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重传&lt;/strong&gt; ：发送方收到NAK后，重传出错的分组&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是加上了两者对话的操作，FSM便是&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Rdt2.1: ACK包纠错&lt;/h3&gt;
&lt;p&gt;如果我们的ACK包和NAK包错了，那么自然会&lt;strong&gt;选择再传一遍&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;但是接收方会收到&lt;strong&gt;冗余分组&lt;/strong&gt; ，接受方由于不知道上一次的ACK/NAK是否正确收到，对于这个分组&lt;strong&gt;是新的还是重传&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个问题的解决方案是** 加上1bit的标志码**，由于是停等，我们只要区分** 上一次的NAK以及这一次的ACK出**, 而区分两个东西，只要用1bit就可以了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发送方：在状态0&amp;#x26;1之间进行跳转&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;状态和当前不符合的就是ACK出错分组&lt;/li&gt;
&lt;li&gt;NAK为传输出错&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果收到ACK且状态相同，则跳转到下一个状态&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接收方：也在0，1之间跳转&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;如果收到正确的序号正确的分组，转移状态&lt;/li&gt;
&lt;li&gt;否则发送ACK/NAK&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Rdt2.2:简化Rdt2.1&lt;/h3&gt;
&lt;p&gt;我们发现再Rdt2.1中，NAK的功能有点少，实际上可以和ACK错误序号规成一类，因此我们&lt;strong&gt;去除NAK这个包&lt;/strong&gt; ，得到Rdt2.2&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发送端：如果收到了与预期不同的ACK/出错的分组，那么重发当前分组&lt;/li&gt;
&lt;li&gt;接受端：如果收到了出错/非预期的分组，重发最近的ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Rdt3.0:解决丢包现象(停等协议)&lt;/h3&gt;
&lt;p&gt;理论上我们收到了一个包之后会进行回应，但是如果&lt;strong&gt;中间丢包&lt;/strong&gt;,那么就没有回应，接收方和发送方都卡住了，解决方案是** 加一个计时器，如果超时，那么就重新发送包**&lt;/p&gt;
&lt;h3&gt;GBN协议:流水线可靠数据传输协议&lt;/h3&gt;
&lt;p&gt;Rdt3.0看上去已经解决了所有问题，但是考虑&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;** example**:考虑1Gbps link,30ms RTT,1KB packet&lt;br&gt;
我们总共花了 $\dfrac{L}{R}$ =8ms去传输，但是传输的时间为 $30ms$ ,而这30ms中间完全空闲下来，利用率过低！！！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以发现，停等协议中大量时间花在等上面了，我们需要让** 发送方在有大量分组排队时不要停下来**，具体的解决方案是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先将分组进行&lt;strong&gt;排序&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;序号范围&lt;/strong&gt; ：我们会同时考虑序号范围内部的分组&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当前序号范围内，包括未发送，和已发送未确认两种分组，如果收到ACK，那么就去除出我们的序号范围&lt;/p&gt;
&lt;p&gt;序号范围的长度(&lt;strong&gt;sliding windows&lt;/strong&gt; )，基序号&lt;strong&gt;base&lt;/strong&gt;,从而我们的序号范围就是[base,base+sliding windows-1]&lt;/p&gt;
&lt;p&gt;而我们的GBN的方式就是:** 考虑移动序号范围，如果丢包，就全部重新传输**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每时每刻按照base开始的顺序发送pkt&lt;/li&gt;
&lt;li&gt;如果收到了&lt;strong&gt;base&lt;/strong&gt; 的ACK，那么base+=1;&lt;/li&gt;
&lt;li&gt;否则等到计时器中止，从base重新开始传输&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;SR协议：选择重传&lt;/h3&gt;
&lt;p&gt;GBN协议的坏处是丢包之后会像sliding windows内的所有的包进行重新传输，这显然有点浪费&lt;/p&gt;
&lt;p&gt;可行的思路是:对于当前sliding windows&lt;strong&gt;中所有的包设置一个定时器，当ACK_base收到之后，移动sliding windows&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;TCP&lt;/h2&gt;
&lt;p&gt;基于以上可靠数据传输，我们由此改进得到TCP的数据传输模式&lt;/p&gt;
&lt;h3&gt;TCP报文结构&lt;/h3&gt;
&lt;p&gt;与UDP类似，但是加上了一些确定** 分组信息，是否正确接收**的字段，因此一般的TCP报文包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;源端口号&amp;#x26;&amp;#x26;目的端口号: 方便进行ACK传输，校验是否正确收到&lt;/li&gt;
&lt;li&gt;检验和(同UDP), 接收窗口字段(进行拥塞控制，控制网络流量)&lt;/li&gt;
&lt;li&gt;序号&amp;#x26;&amp;#x26;确认号：确定该分组传输的数据是整体报文的那个位置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TCP将数据看成&lt;strong&gt;无结构，有序&lt;/strong&gt; 的字节流，在传输前，报文的&lt;strong&gt;每个字节都对应了一个独特的序号&lt;/strong&gt; ，而分割时，会以类似&lt;strong&gt;0-1000号字节为报文1，1000-2000号字节为报文2&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;序号：对于&lt;strong&gt;分组的序号&lt;/strong&gt;,就是这个分组** 传输的报文片段的第一个字节对应的序号**，比如对于传输1000-2000号字节的报文，其序号就是1000&lt;/li&gt;
&lt;li&gt;确认号：&lt;strong&gt;期待收到的下一个分组的序号&lt;/strong&gt; ，也就是已经确认的报文序号的下一个，比如我们已经收到了0-1000(分组1)，1001-2000（分组2），3000-4000(分组4)，那么我们的这个报文的确认号&lt;strong&gt;就是2001&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP RTT管理&lt;/h3&gt;
&lt;p&gt;RTT(超时时间)是定时器的重要组成部分，但是对于网络而言，其网速是动态变化的，因此TCP会根据** 收到的超时信息**动态调整&lt;/p&gt;
&lt;p&gt;对于我们的超时的时间限制 $X$ 作为一个随机变量，需要考虑整体的均值&amp;#x26;&amp;#x26;波动幅度，从而进行动态调整，假设** 对于每一个时刻的RTT的均值方差为 $EstimatedRTT,DevRTT$** , 收到一个新的** Sample RTT**（反映当前时段的网速）我们会使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;均值更新： $EstimatedRTT=(1-\alpha)\cdot EstimatedRTT+\alpha \cdot SampleRTT$ 来更新RTT的值&lt;/li&gt;
&lt;li&gt;方差更新： $DevRTT=(1-\beta)\cdot DevRTT +\beta \cdot |SampleRTT-EstimatedRTT$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;并且使用 $TimeoutInterval=EstimatedRTT+4\cdot DevRTT$ 去更新超时的时间限制&lt;/p&gt;
&lt;h3&gt;TCP可靠数据传输&lt;/h3&gt;
&lt;p&gt;TCP的主要特点是在&lt;strong&gt;在接收端可以通过确认号&amp;#x26;&amp;#x26;序列号进行缓存&lt;/strong&gt; ，可以看成是GBN&amp;#x26;SR的结合，具体步骤为&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;发送方&lt;/strong&gt; ：每发送一个报文，启动一个计时器&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果收到了ACK，那么中止计时器&lt;/li&gt;
&lt;li&gt;如果计时器超过RTT,那么重发当前报文&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;接收方&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果收到了比预期序号大，但是正确的包，进行缓存&lt;/li&gt;
&lt;li&gt;返回预期序号对应ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果发生连接断开导致的丢包，会使用RTT进行重传。而如果发生因为意外导致的丢包时间，我们使用&lt;strong&gt;快速重传&lt;/strong&gt; 机制：&lt;strong&gt;如果收到了3个重复的ACK,那么重发丢失的报文&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;** 举个例子**：如果发送方要发送1，2，3，4，5几个报文，2号报文丢了&lt;br&gt;
发送方：发送1，2，3，4，5，但是收到了1，2，2，2，2，于是又发送了一遍2&lt;br&gt;
接收方：收到了1，3，4，5于是将3，4，5存了起来，但是还是返回的预期是2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;TCP 拥塞控制&lt;/h3&gt;
&lt;p&gt;为什么会有拥塞问题？主要是因为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;在原本的假设中，网络层中的路由器有无限大的缓存&lt;/strong&gt; ，但是实际中，有限缓存会产生如上一篇文章中的，&lt;strong&gt;排队时间过长的问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;即使这样，如果有多台路由器，排队时间过长导致缓存溢出，路由器会开始丢包，这就导致&lt;strong&gt;之前路由器传输所画时间全部浪费了&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此解决拥塞问题便成了改进TCP性能的重要问题，而这个过程有几个问题需要考虑&lt;/p&gt;
&lt;p&gt;(1) 发送端** 如何探测到拥塞问题** （2）发送方采取** 什么机制&lt;strong&gt;去限制发送速率 （3）&lt;/strong&gt; 机制的具体实现**&lt;/p&gt;
&lt;p&gt;** 1.如何探测到拥塞问题**&lt;/p&gt;
&lt;p&gt;由于我们发送方检测报文有无收到，只能通过自己的定时器以及接收方的返回信息，因此我们的探测途径有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定时器超时&lt;/li&gt;
&lt;li&gt;收到连续的3个ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就表明没有收到，可以认为是&lt;strong&gt;由于拥塞问题导致的问题&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;** 2.采取什么机制限制发送速率**&lt;/p&gt;
&lt;p&gt;最为经典的限制速率的方式就是** 运行时添加一个额外的变量拥塞窗口(congestion window)**&lt;/p&gt;
&lt;p&gt;$cwnd(congestion window)=发送了，但是没有确认的字节数目$&lt;/p&gt;
&lt;p&gt;而我们的发送速率会用 $cwnd/RTT 字节/s$ , 这可以保证** 平均下来，在RTT的时间内，有cwnd的数据可以收到回复**，从而通过控制发送速率，保证能在RTT的时间内收到回复&lt;/p&gt;
&lt;p&gt;** 3.机制的具体实现**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接刚刚建立时，cwnd=1mss&lt;/li&gt;
&lt;li&gt;控制threshold作为分水岭，如果cwnd低于限制，使用慢启动(指数上涨cwnd),否则执行AIMD(线性增长cwnd)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果发生了丢包&lt;/strong&gt; ：threshold设置为当前cwnd一半&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;若收到了3次重复ACK&lt;/strong&gt;,令 $cwnd=threshold+3*MSS$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;若发生了超时现象&lt;/strong&gt; ： $cwnd=1*MSS$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_08.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;以上就是UDP&amp;#x26;&amp;#x26;TCP，以及如何得到TCP的基本过程。尤其是对于TCP的推导过程，对于丢包，堵塞控制，检验错误。。。这种对于一个应用，需要实现若干功能，逐步实现并且提升性能的过程，能为我们之后的研究有更多启发性的思路。&lt;/p&gt;</content:encoded><h:img src="/_astro/titan4.DdQNxXIQ.jpg"/><enclosure url="/_astro/titan4.DdQNxXIQ.jpg"/></item><item><title>计算系统概论2：LC-3基本指令以及数据传输</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/computer-systems-2-lc3-instructions-data-transfer/computer-systems-2-lc3-instructions-data-transfer</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/computer-systems-2-lc3-instructions-data-transfer/computer-systems-2-lc3-instructions-data-transfer</guid><description>计算系统概论2：LC-3基本指令以及数据传输</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;LC-3是冯诺依曼机的一个简单样例，也是考试的重点，下面来整理一下LC-3的基本结构，指令以及有趣的例题&lt;/p&gt;
&lt;h2&gt;LC-3基本结构&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;存储器&lt;/h3&gt;
&lt;p&gt;Memory部分主要包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt; :总共为 $2^{16}$ 个16bit的单元，用来存储数据，形式如 $x3000: 0001 010 000 000 001$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MAR&lt;/strong&gt; :存储需要拿取数据的地址，比如如果我们需要拿取 $x3000$ 位置的数据，那么MAR中就是 $x3000=0011\ 0\times 12$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDR&lt;/strong&gt; :存储我们MAR对应地址的值，同样的例子，有 $MDR$ 中为 $0001\ 010\ 000 \ 0 \ 00 \ 001$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IR&lt;/strong&gt; :存储当前的数据，可以是MDR传过来的值，也可以是ALU传过来的值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以及&lt;strong&gt;PC&lt;/strong&gt; :特殊的寄存器，存储下一条要执行的指令在内存中的地址，比如我们要执行 $x3000$ ,那么PC中就是 $x3000$ ,执行完成之后变成 $x3001$&lt;/p&gt;
&lt;h3&gt;中央处理器部分&lt;/h3&gt;
&lt;p&gt;LC-3的中央处理主要包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FINITE-State machine&lt;/strong&gt; ：用来解析从Memory取出来的指令，并且对于数据进行代数操作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NZP&amp;#x26;&amp;#x26;Logic&lt;/strong&gt; ：存储当前数据状态，每一次指令操作后会根据结果进行更新。(用于条件判断)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Register&lt;/strong&gt; :寄存器，暂时保存数据，LC-3中总共有R0-7共8个寄存器unit，可以使用3bit标志那个unit&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ALU&lt;/strong&gt; :根据有限状态机，以及Register传过来的值进行操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上就是LC-3的主要元器件，对于别的MUX（选择器),以及SEXT(加长)属于细节，不太需要考虑。&lt;/p&gt;
&lt;p&gt;对于一个cycle的基本操作：需要注意，对于LC3中所有的指令也是16bit的数据，同样也会存储在Memory中，&lt;strong&gt;数据就是指令，指令就是数据&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;具体的指令&lt;/h2&gt;
&lt;p&gt;了解了基本的工作流程，我们就需要介绍具体的指令了，我们LC3的指令包括：** 运算指令(对于register)，控制指令（控制整体运行），数据移动指令(控制Memory&amp;#x26;&amp;#x26;register)**&lt;/p&gt;
&lt;h3&gt;运算指令&lt;/h3&gt;
&lt;p&gt;** 1.NOT**&lt;/p&gt;
&lt;p&gt;LC3： $1001,Dst(3bit),Src(3bit),111111$&lt;/p&gt;
&lt;p&gt;表示not指令的opcode是1001，将 $R_{src}$ 中的数据取反，存入 $R_{dst}$ 中&lt;/p&gt;
&lt;p&gt;对于5中的数据通路就是: $从Register中取出R_{Src}\Rightarrow ALU接受取反指令并且进行取反 \Rightarrow 经过数据总线存入R_{Dsr}$&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;** 2.ADD/AND**(Register模式)&lt;/p&gt;
&lt;p&gt;** ADD**: $0001,Dst(3bit),Src1(3bit),000,Src2(3bit)$&lt;/p&gt;
&lt;p&gt;** AND**: $0101,Dst(3bit),Src1(3bit),000,Src2(3bit)$&lt;/p&gt;
&lt;p&gt;表示ADD/And(Register mode)是将 $R_{Src1},R_{Src2}$ 中的数据进行ADD/AND操作，并且将结果存进 $R_{Dst}$ 中&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;其数据通路于NOT类似，就不细说了&lt;/p&gt;
&lt;p&gt;** 3.ADD/AND**(Immediate模式)&lt;/p&gt;
&lt;p&gt;** ADD**: $0001,Dst(3bit),Src1(3bit),1,Imm5(5bit)$&lt;/p&gt;
&lt;p&gt;** AND**: $0101,Dst(3bit),Src1(3bit),1,Imm5(5bit)$&lt;/p&gt;
&lt;p&gt;表示ADD/And(Immediate mode)是将 $R_{Src1}$ 中的数据,与** 经过符号扩展的 $Imm5$** 进行ADD/AND操作，并且将结果存进 $R_{Dst}$ 中&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_05.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;要注意，这里的Imm5是有符号数，因此其范围是**-16-15**&lt;/p&gt;
&lt;h3&gt;数据移动指令&lt;/h3&gt;
&lt;p&gt;数据移动指令，涉及到从Memory与Register之间的数据转换，而具体操作包括** 取地址，取地址对应的数，取地址对应的地址处的数，取特定位置的数**，以及相应的存储操作&lt;/p&gt;
&lt;p&gt;** 1.LD/ST**:取地址对应的数&lt;/p&gt;
&lt;p&gt;** LD**: $0010,Dst(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;** ST**: $0011,Dst(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;LD表示将 $M[PC_{+1}+PCoffset9]\Rightarrow R_{Dst}$ ,而ST则是正好相反&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_06.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如图所示，LD的数据存储过程中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$MAR=PC_{+1}+PCoffset9$&lt;/li&gt;
&lt;li&gt;$MDR=M[MAR]$&lt;/li&gt;
&lt;li&gt;最后 $R_{Dst}=MDR$ ，并且根据&lt;strong&gt;MDR的值去更新NZP&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样的道理，对于ST而言&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$MAR=PC_{+1}+PCoffset9,MDR+R_{Dst},Memory[MAR]=MDR$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2.LDI/STI&lt;/strong&gt; :取地址对应的地址里面的数&lt;/p&gt;
&lt;p&gt;如果前一步可以认为是c语言中的 $a=x$ ,那么这一步可以认为 $a=*x$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LDI&lt;/strong&gt; : $1010,Dst(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STI&lt;/strong&gt; : $1011,Dst(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;LDI表示将 $M[M[PC_{+1}+PCoffset9]]\Rightarrow R_{Dst}$ ,而STI则正好相反&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_07.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;对于LDI的&lt;strong&gt;MAR,MDR&lt;/strong&gt; 的变化为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Step1: $MAR=PC_{+1}+PCoffset9$&lt;/li&gt;
&lt;li&gt;Step2: $MDR=M[MAR]$ ,然后将MDR的值赋予MAR&lt;/li&gt;
&lt;li&gt;Step3: $MDR=M[MAR]$ ,最后有 $R_{Dst}=MDR$ 并且更新NZP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样的道理，对于STI就是 $M[M[PC_{+1}+PCoffset9]]=R_{Dst}$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.LDR/STR&lt;/strong&gt; :取特定位置的数&lt;/p&gt;
&lt;p&gt;由于之前我们只能取出 $PC_{+1}+PCoffset9$ 的数，但是 $PCoffset9$ 只能表示**-256-255** 的数，这个范围有限，而LDR/STR的目的就是&lt;strong&gt;将M[存储在register中的一个数]赋予Destination&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pic1.zhimg.com/v2-10b858e7ad20234581acc6217f3beb8a_1440w.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;** LDR**: $0110,Dst(3bit),Base(3bit),offset6(6bit)$&lt;/p&gt;
&lt;p&gt;** STR**: $0111,Dst(3bit),Base(3bit),offset6(6bit)$&lt;/p&gt;
&lt;p&gt;LDR表示 $M[R_{Base}+offset6]=R_{Src}$ ,STR则正好相反。&lt;/p&gt;
&lt;p&gt;对于LDR中的** MAR,MDR**变化为&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Step1: $MAR=R_{Base}+SEXT[offset6]$&lt;/li&gt;
&lt;li&gt;Step2: $MDR=M[MAR],R_{Dst}=MDR$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4.LEA&lt;/strong&gt; :存储地址&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LEA&lt;/strong&gt; : $1110,Dst(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;LEA表示的就是将 $R_{Dst}=PC_{+1}+PCoffset9$ ,计算出这个结果之后&lt;strong&gt;直接存储进 $R_{Dst}$ ,并没有经过MDR/MAR&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_09.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;控制指令&lt;/h3&gt;
&lt;p&gt;** BR**: $0000,nzp(3bit),PCoffset9(9bit)$&lt;/p&gt;
&lt;p&gt;其过程就是** 若NZP中有符合nzp中的东西，那么跳转到 $PC_{+1}+PCoffset9$**&lt;/p&gt;
&lt;p&gt;同样还有像TRAP指令，这个基本就是背诵指令，主要用的就是** TRAP**&lt;/p&gt;
&lt;p&gt;以上就是我们最基本的LC3的指令，我们需要** 熟练掌握数据通路，MAR/MDR的值，以及每条指令的过程**,之后我们会进行更多相关例题的训练。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BQ66dyS4.jpg"/><enclosure url="/_astro/background.BQ66dyS4.jpg"/></item><item><title>离散数学(3):基于欧拉定理研究群</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/discrete-mathematics-3-group-theory-euler/discrete-mathematics-3-group-theory-euler</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/discrete-mathematics-3-group-theory-euler/discrete-mathematics-3-group-theory-euler</guid><description>离散数学(3):基于欧拉定理研究群</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;邵老师将群论的方式非常的特别，对于每一个概念的引入做的非常非常的清晰，美中不足的就是对于课程中的主线不是特别的明晰。&lt;/p&gt;
&lt;p&gt;在回顾了一下讲义之后，突然发现如果以&lt;strong&gt;欧拉定理&lt;/strong&gt; 类比去一步步推导群的性质会非常自然，对于每个概念对应的最重要的性质也会有更好的理解。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;从群，到研究有限群的性质，然后到考虑阶的性质，我们的目标是&lt;strong&gt;发现一个类似于欧拉定理的东西&lt;/strong&gt; ，然后迁移了&lt;strong&gt;缩系的乘法的概念&lt;/strong&gt; 到陪集分解，最后到使用循环群引入群同构的概念。&lt;/p&gt;</content:encoded><h:img src="/_astro/background.D-iH0YN4.jpg"/><enclosure url="/_astro/background.D-iH0YN4.jpg"/></item><item><title>离散数学(4):环域&amp;理想初步</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/discrete-mathematics-4-ring-field-ideal/discrete-mathematics-4-ring-field-ideal</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/discrete-mathematics-4-ring-field-ideal/discrete-mathematics-4-ring-field-ideal</guid><description>离散数学(4):环域&amp;理想初步</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;环&lt;/strong&gt; 是更为广泛的，将Z上的加法和乘法抽象出来的概念，&lt;strong&gt;域&lt;/strong&gt; 则是环加上可逆条件。&lt;/p&gt;
&lt;p&gt;研究0元引出了整环的概念，而研究”子环”让我们进一步思考理想的问题。而通过研究理想(&lt;strong&gt;Z,Z[x]&lt;/strong&gt; 两个例子的理想的特性)，我们抽象出了主理想的概念，这对应着&lt;strong&gt;初等数论中的最大公约数&lt;/strong&gt; 概念。&lt;/p&gt;
&lt;p&gt;最后，我们为了研究“素数”这个概念，引入了素元和不可约元的概念，这个会在后续的文章中进行深入研究&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BvRCTbmF.jpg"/><enclosure url="/_astro/background.BvRCTbmF.jpg"/></item><item><title>运筹学 Part 1——线性规划问题求解方法</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/operations-research-part1-linear-programming/operations-research-part1-linear-programming</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/operations-research-part1-linear-programming/operations-research-part1-linear-programming</guid><description>运筹学 Part 1——线性规划问题求解方法</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;运筹学 Part 1——线性规划问题求解方法&lt;/h2&gt;
&lt;p&gt;这个学期我选了大三的运筹学，所谓的运筹学，就是在约束条件下如何求解一个函数的极值。像CS229中的SVM部分(KKT条件推导)，而我们的最为简单的约束条件以及目标函数就是&lt;strong&gt;线性函数&lt;/strong&gt; ，因此线性规划问题的求解就非常的重要&lt;/p&gt;
&lt;h2&gt;线性规划问题的一般形式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;目标函数&lt;/strong&gt; ：由于目标函数为线性的，我们要求 $c^T x$ 的最值，由于 $max\     c^T x\Leftrightarrow min\  -c^Tx$ ,从而对于任意线性规划问题，**目标函数可以转换成 $min\  c^T x$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;线性约束&lt;/strong&gt; ：对于我们的约束而言，可能有 $Ax\geq b, Ax=b, Ax\leq b$ ,对于等式是最好处理的，我们考虑将不等式化为等式=&gt;考虑高中数竞中的小技巧:将差值设出来， $Ax\geq b\Leftrightarrow Ax-s=b, s\geq 0$ ,其中s的维度和A的行数相同。&lt;/p&gt;
&lt;p&gt;同样的道理有 $Ax\leq b \Leftrightarrow Ax+t=b,t\geq 0 $ 从而我们所有的&lt;strong&gt;约束条件都可以表示成 $Ax=b$ 的形式&lt;/strong&gt; (最多添加几个人工变量)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;变量范围：&lt;/strong&gt; 在线性约束中我们添加了若干个人工变量,这些变量的都是大于等于0的，因此我们希望对于原有变量也全部大于等于0.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于某一个变量 $x_i$ 而言，如果 $x_i$ 有下界，那么用 $x&apos;&lt;em&gt;i(x_i-low&lt;/em&gt;{bound})$ 代替原有的 $x_i$ 即有 $x_i&apos;\geq 0$&lt;/li&gt;
&lt;li&gt;若 $x_i$ 没有下界，使用 $x_i=y_i-z_i,y_i\geq 0，z_i\geq 0$ 代替从而有所有变量都有下界0&lt;/li&gt;
&lt;li&gt;如果 $x_i$ 有上界 $x_i\leq u_i$ ,添加人工变量 $y_i$ 以及约束 $x_i+y_i=u_i$ 此时有 $u_i\geq 0$ ,对于 $x_i$ 的处理方法同没有下界&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;经过以上的操作，我们有  $ \begin{align*} \min \quad &amp;#x26; \mathbf{c}^\top \mathbf{x} \ \text{s.t.} \quad &amp;#x26; A\mathbf{x} = \mathbf{b} \ &amp;#x26; \mathbf{x} \geq \mathbf{0}. \end{align*} $ 这样的形式称为&lt;strong&gt;线性规划的一般形式&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;线性规划解的不同刻画(简略)&lt;/h2&gt;
&lt;p&gt;我们来介绍几个概念&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可行域&lt;/strong&gt; $P={x\in R^n|Ax=b,x\geq 0}$ 称为问题的可行域&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;凸集&lt;/strong&gt; :一个集合P称为凸集， $\forall A,B\in P ,\lambda\in[0,1]\Rightarrow \lambda A+(1-\lambda B)\in P$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;容易发现所有线性规划问题的可行域都是凸集&lt;/p&gt;
&lt;p&gt;对于线性规划问题的解，我们在高中的时候做题，顶点，边界为常见的极值点的位置，我们想要刻画这个顶点概念&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;极点&lt;/strong&gt; ： $\exists C, \forall x\in P \Rightarrow c^Tx&gt;c^T \hat{x}$ 此时我们称 $\hat{x}$ 为极点(一个多面体的一个角)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;顶点&lt;/strong&gt; ：x称为P的顶点，如果 $\not\forall A,B\in P (A,B\neq x),\lambda\in [0,1], x\neq\lambda A+(1-\lambda) B$ (也就是不存在有点与它共线)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以发现顶点和极点是”等价的”，但是在计算的时候并不方便，于是有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基解&lt;/strong&gt; ：如果x为n维向量，在P中的n个线性无关的约束构成的线性方程组有唯一解，这个解为P的一个基解&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可行基解&lt;/strong&gt; ：如果基解在P中，那么称之为P的可行基解&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以证明：&lt;strong&gt;在线性规划问题(凸集)中，极点，顶点，可行基解是等价的，对于线性规划的极值，要么在无穷处取到，要么可以在一个极点处取到&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从而我们可以将一个不容易计算的** “顶点，角”**转换称计算一个线性方程组的问题。&lt;/p&gt;
&lt;p&gt;对于这个定理的证明可以看我的手写笔记：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;单纯形法&lt;/h2&gt;
&lt;p&gt;如果我们直接将每一个可行基解求出来，然后计算其对应的目标值，总共的基解数目为 $C^n_m$ ，而对于求解一个线性方程组，也就是求逆的操作，复杂度为 $n^3$ ，总共就是 $C^n_m n^3$ ,太大了。&lt;/p&gt;
&lt;p&gt;因此单纯形法的思路就是** 从一个基解开始，通过一个损失函数找到可以使目标函数进行改善的下一个可行基解，然后进行解的变换并继续迭代下去**&lt;/p&gt;
&lt;h3&gt;损失函数&lt;/h3&gt;
&lt;p&gt;对于标准的线性规划问题，我们一个可行基解什么时候是最优的，此时我们借鉴** 理论力学中的虚功原理：找一个小的位移！！**&lt;/p&gt;
&lt;p&gt;由于我们的可行基解可以看成若干个平面的交对应的顶点，如果想要移动到一个新的基解上，我们考虑的是进行** 顶点对应平面的替换**&lt;/p&gt;
&lt;p&gt;即为如果 $x_B$ 是由 $A_1,A_2,...A_n$ 构成的，那么就对于平面进行替换成 $A&apos;_1,A&apos;_2,....A&apos;_n$ 得到 $x&apos;_B$&lt;/p&gt;
&lt;p&gt;而对于平面的替换的话，参考排序算法，自然想到进行一一的替换 $(A_1,A_2,...A_n)\Rightarrow (A&apos;_1,A_2,...A_n)\Rightarrow (A&apos;_1,A&apos;_2,...A&apos;_n)$&lt;/p&gt;
&lt;p&gt;从而可以做到依次的抛弃 $A_1,...A_n$ 这些平面&lt;/p&gt;
&lt;p&gt;如果对于 $Ax=b,\tilde{x}=x+\theta d$ 进行可行基的划分,就是 $A=(B,N),x=(x_B,x_N)^T,c=(c_B,c_N)^T,d=(d_B,d_N)^T$&lt;/p&gt;
&lt;p&gt;而依次替换一个平面就是在数学上的表示就是&lt;/p&gt;
&lt;p&gt;$ \begin{cases} d_j = 1, &amp;#x26; j \in N, \ d_i = 0, &amp;#x26; i \in N, ; i \ne j , \end{cases} $&lt;/p&gt;
&lt;p&gt;由于移动后的点需要满足整体约束(在这个多边形表面上)，有 $0=Ad=Bd_B+A_j\Rightarrow d_B =-B^{-1} A_j$&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;也就是图中的 $A_2,A_3$ 交线的方向向量&lt;/p&gt;
&lt;p&gt;考虑进行一些小扰动，目标函数就有&lt;/p&gt;
&lt;p&gt;$\begin{aligned} z &amp;#x26;= c_B^{\top}(x_B + \theta d_B) + \theta c_N^{\top} d_N \   &amp;#x26;= c_B^{\top}(x_B - \theta \mathbf{B}^{-1} A_j) + \theta c_j \end{aligned}$&lt;/p&gt;
&lt;p&gt;相比于原目标 $c^T x$ 变化量为 $z - c^{\top} x = \theta \bigl(c_j - c_B^{\top} \mathbf{B}^{-1} A_j \bigr)$&lt;/p&gt;
&lt;p&gt;因此对于** 远离j这个基方向对于目标函数的影响，就是 $\hat{c}_j=c_j-c_B^{\top} B^{-1} A_j $** ，从而损失函数也可以理解成对于这个** 基方向的导数！**&lt;/p&gt;
&lt;h3&gt;转轴运算&lt;/h3&gt;
&lt;p&gt;如果我们最优判定中，对于某一个可行基解 $x=(B^{-1}b\  0)$ 可以计算其损失函数，如果对于某一个基方向 $x_j$ 有损失函数（导数） $c_j&amp;#x3C;0$ ，就说明对于j** 这个基方向进行移动，目标函数会减小**，这是我们需要的&lt;/p&gt;
&lt;p&gt;具体操作为&lt;/p&gt;
&lt;p&gt;对于 $\tilde{x}=x+\theta d,d=-B^{-1}A_j$ ，即为&lt;/p&gt;
&lt;p&gt;$ \begin{pmatrix} \tilde{x}&lt;em&gt;{B_1} \ \tilde{x}&lt;/em&gt;{B_2} \ \vdots \ \tilde{x}&lt;em&gt;{B_m} \end{pmatrix} = \begin{pmatrix} x&lt;/em&gt;{B_1} \ x_{B_2} \ \vdots \ x_{B_m} \end{pmatrix} + \theta \begin{pmatrix} d_{B_1} \ d_{B_2} \ \vdots \ d_{B_m} \end{pmatrix}. $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$d_{B_i}\geq 0$ 恒成立，如果有 $c_j&amp;#x3C;0$ ，那么在该点不是最值，沿着 $d_B$ 目标函数会不断增加，因此此时为&lt;strong&gt;无界解&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果存在i，有 $d_{B_i}&amp;#x3C;0$ ，那么在该方向上继续移动，会有&lt;strong&gt;移动距离的上限&lt;/strong&gt; ， $\theta \leq -x_{B_i}/d_{B_i}$ ,因此我们取最大的 $\theta$ ,记成 $\begin{equation}   \theta^* = \min_{{i \mid d_{B_i} &amp;#x3C; 0}} \left( -\frac{x_{B_i}}{d_{B_i}} \right).   \end{equation}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从而我们得到了新的可行解&lt;/p&gt;
&lt;p&gt;$\tilde{x} = \bigl(x_{B_1}, \cdots, x_{B_{r-1}}, 0, x_{B_{r+1}}, \cdots, x_{B_m}, 0, \cdots, x_j, \cdots, 0 \bigr)^{\top}$&lt;/p&gt;
&lt;p&gt;从而通过&lt;strong&gt;替换基变量 $x_{B_r}$ 与非基变量 $x_j$ 得到新的可行解，这就是转轴运算&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;** 对于单纯形法的几何&amp;#x26;代数的对应：**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可行基解&lt;/strong&gt; 就是多面体的&lt;strong&gt;顶点&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;而&lt;strong&gt;损失函数(最优判定条件)&lt;/strong&gt; 就是目标函数对于变量 $x_j$ 的&lt;strong&gt;导数&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;每一步我们都找到一个 $\dfrac{\partial c^T x}{\partial x_j}(c_j-c_B^{\top} B^{-1} A_j)$ 小于&lt;strong&gt;0的方向&lt;/strong&gt; (对应第一部分)&lt;/li&gt;
&lt;li&gt;然后沿着这个方向进行移动，直到找到第一个可行基解(&lt;strong&gt;转轴运算&lt;/strong&gt; )&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;记住这个图片之后，再翻译成代数语言就可以了&lt;/p&gt;
&lt;h2&gt;单纯形表法&lt;/h2&gt;
&lt;p&gt;由于我们的单纯形法每一步将可行基解中的一个变量从大于0变成0，并且将另外一个0变成大于0&lt;/p&gt;
&lt;p&gt;其对应的基矩阵 $B\Rightarrow \tilde{B}$ 每一次进行迭代之后会&lt;strong&gt;添加一列，再减少一列&lt;/strong&gt; ，可以发现 $B^{-1},\tilde{B}^{-1}$ 之间会有许多关联&lt;/p&gt;
&lt;p&gt;考虑相乘，可以发现 $\mathbf{B}^{-1} \tilde{\mathbf{B}} = [ \mathbf{e}_1, \mathbf{e}&lt;em&gt;2, \dots, \mathbf{e}&lt;/em&gt;{r-1}, \mathbf{u}&lt;em&gt;r, \mathbf{e}&lt;/em&gt;{r+1}, \dots, \mathbf{e}_m ]$ 中， $u_r=-d_B=B^{-1}A_j$&lt;/p&gt;
&lt;p&gt;因此只需要对于 $B^{-1}A$ 进行线性变换，将 $u_r$ 对应的列变成 $e_r$ ，就可以得到 $\tilde{B}^{-1}A$&lt;/p&gt;
&lt;p&gt;更进一步，我们可以同时对于&lt;strong&gt;入基变量,损失函数(导数)，函数值进行同样的线性变换&lt;/strong&gt;,组成一张表，每一步的操作就是对于表的线性变换&lt;/p&gt;
&lt;p&gt;$ \left[ \begin{array}{c|c} -c_B^\top B^{-1} b &amp;#x26; c^\top - c_B^\top B^{-1} A \ \hline B^{-1} b &amp;#x26; B^{-1} A \end{array} \right] $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step1&lt;/strong&gt; 找到导数小于0的index：在第一行中找到一个值小于0的值对应的列&lt;strong&gt;prepare index&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step2&lt;/strong&gt; 找到在该方向上的第一个”平面”：在prepare index这一列上找到比值 $\begin{equation}   \theta^* = \min_{{i \mid d_{B_i} &amp;#x3C; 0}} \left( -\frac{x_{B_i}}{d_{B_i}} \right).   \end{equation}$&lt;br&gt;
并且进行入基，出基操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个例子为&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_04.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;初始可行基解的寻找&lt;/h2&gt;
&lt;p&gt;对于初始的可行基解的寻找，我们希望可以有类似与例子一样的基矩阵为单位阵的结构，观察到例子中的线性规划方程为 $Ax\leq b$ 的变种，即为 $Ax+y=b$ ,因此我们也进行同样的构造。考虑辅助问题&lt;/p&gt;
&lt;p&gt;$ \begin{align*} \min \quad &amp;#x26; \mathbf{1}^\top \mathbf{y} \ \text{s.t.} \quad &amp;#x26; A\mathbf{x} + \mathbf{y} = \mathbf{b} \ &amp;#x26; \mathbf{x} \geq \mathbf{0},; \mathbf{y} \geq \mathbf{0}. \end{align*} $&lt;/p&gt;
&lt;p&gt;对于这个问题可行解非常容易发现为 $(x,y)=(0,b)$ ,从而可以构造单纯形表，最后得到最优解&lt;/p&gt;
&lt;p&gt;如果我们的原问题有可行解存在，那么可以取 $(x,y)=(x,0)$ 此时有最小值为0，而由于 $y\geq 0$ 因此目标函数 $z\geq 0$ ，因此假设我们辅助问题的最优解为 $(\hat{x},\hat{y})$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若 $\hat{y}$ 大于0，那么有 $z=1^T y&gt;0$ ,说明原问题&lt;strong&gt;没有可行解&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;若 $\hat{y}=0$ 此时得到的 $\hat{x}$ 就是一组可行解，从而可以&lt;strong&gt;进行正常的单纯形法&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;一些特殊的情况&lt;/h2&gt;
&lt;p&gt;** 循环解情况：**&lt;/p&gt;
&lt;p&gt;如果在单纯形表中入基变量中有多个0出现，那么就有可能发生两个变量 $i,j$ 来回入，出，入，出的情况，因此我们在进行入基变量选取的时候** Bland rule可以保证最后一定收敛**(可能会牺牲一点点的复杂度)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若非基向量中，存在多个 $\hat{c_i}&amp;#x3C;0$ 选取i最小的下标&lt;/li&gt;
&lt;li&gt;出基的过程中，计算下标r使得 $\begin{equation}   \theta^* = \min_{{i \mid d_{B_i} &amp;#x3C; 0}} \left( -\frac{x_{B_i}}{d_{B_i}} \right).   \end{equation}$&lt;br&gt;
时，选取最小的下标 $B_r$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;退化解情况：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果我们的可行解 $x=(x_B,x_N),x_N=0$ 理论上 $x_B$ 有A.rank的大小，但是如果 $x_B$ 中有0的话，那么就无法分辨那个是入基变量，那个是别的了，对此我们可以：&lt;/p&gt;
&lt;p&gt;** 直接从所有的 $x_i=0$ 中抽取若干个补充到 $x_B$ 中，这样找到的基矩阵也是满足要求的**&lt;/p&gt;
&lt;p&gt;这样做有个前提是矩阵A是满秩的，这样对于任意抽取 $A.rank$ 列也是线性无关的，可以作为基矩阵。&lt;/p&gt;
&lt;h3&gt;代码实现&lt;/h3&gt;
&lt;p&gt;关于实验要求以及我的代码可以参考我的github仓库&lt;/p&gt;
&lt;p&gt;以上我们介绍了线性规划问题的求解思路，从问题的化简，到转换成计算机可以理解的语言，最后到单纯形法这种为了节省时间复杂度设计的东西，一节可能的特殊情况，同时我们也从几何角度理解了单纯形法的变换过程，最后我们进行了代码实现部分。总体而言，单纯形法还是非常漂亮美丽的算法&lt;/p&gt;</content:encoded><h:img src="/_astro/background.BpNX50kq.jpg"/><enclosure url="/_astro/background.BpNX50kq.jpg"/></item><item><title>运筹学 Part 2——非线性规划基础</title><link>https://bauklotze.vercel.app/blog/ustc-course-learning/operations-research-part2-nonlinear-programming/operations-research-part2-nonlinear-programming</link><guid isPermaLink="true">https://bauklotze.vercel.app/blog/ustc-course-learning/operations-research-part2-nonlinear-programming/operations-research-part2-nonlinear-programming</guid><description>运筹学 Part 2——非线性规划基础</description><pubDate>Sun, 11 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在线性规划中，所有的等式约束条件，不等式约束以及目标函数都是线性函数，我们是通过&lt;strong&gt;先研究约束条件中点的性质，最后和目标函数的target连起来&lt;/strong&gt; 的思路，而非线性规划我们也会使用类似的思路局部最优解满足条件推导&lt;/p&gt;
&lt;p&gt;对于非线性规划问题&lt;/p&gt;
&lt;p&gt;$ \begin{aligned} \min_{x \in \mathbb{R}^n} \quad &amp;#x26; f(x) \ \text{s.t.} \quad &amp;#x26; g_i(x) \le 0, \quad i = 1, \dots, m, \ &amp;#x26; h_j(x) = 0, \quad j = 1, \dots, p. \end{aligned} $&lt;/p&gt;
&lt;h2&gt;下降方向&lt;/h2&gt;
&lt;p&gt;所谓的下降方向，就是要寻找&lt;strong&gt;往那个方向改变x可以让f(x)&lt;/strong&gt; 更小，于是自然有如下定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt; ：设f(x)为 $R^n$ 上的实函数， $\bar{x}\in R^n$ ，d为非0向量，如果存在 $\delta&gt;0$ 使得 $f(\bar{x}+\lambda d)&amp;#x3C;f(\bar{x}),\forall \lambda \in (0,\delta)$ 称d为f(x)在 $\bar{x}$ 处的&lt;strong&gt;下降方向&lt;/strong&gt; ，下降方向组成的集合为 $\Omega(\bar{x},f)$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;进一步我们的约束以及目标都是可微的，可以发现&lt;strong&gt;当 $\nabla f(\bar{x})^T d&amp;#x3C;0$ 时，此时d显然为下降方向&lt;/strong&gt; ，所以对于目标函数的梯度&lt;strong&gt;可以作为下降方向的重要衡量标准&lt;/strong&gt;,于是有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一阶线性下降方向&lt;/strong&gt; ： $D(\bar{x},S) = { d \in \mathbb{R}^n \mid \nabla f(\bar{x})^\top d &amp;#x3C; 0 }$ 称为一阶线性下降方向&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;可行方向集合&lt;/h2&gt;
&lt;p&gt;下降方向是规定了&lt;strong&gt;往那些方向改变x会让f(x)减小&lt;/strong&gt; ，而&lt;strong&gt;对于约束条件也划定了一个区域，我们的x只能在这个里面游动&lt;/strong&gt; ，因此改变x的是皇后就需要在可行方向集合里面改变&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可行方向集合&lt;/strong&gt; ：设 $\bar{x} \in S,d\in R^n$ ,为非0向量，若存在 $\delta&gt;0$ 使得&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ \bar{x}+\lambda d \in S,\forall \lambda \in (0,\delta) $&lt;/p&gt;
&lt;p&gt;称d为S在 $\bar{x}$ 处的可行方向，将所有的在x处的可行方向记为 $F(\bar{x},S)$ 。&lt;/p&gt;
&lt;p&gt;同样的，如果我们假设所有的h,g都是可微的，那么对于使用Taylor展开，我们仍然可以使用梯度作为衡量标准，于是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一阶不等式可行方向&lt;/strong&gt; ： $F_{\bar{x},S} = { d \mid    \nabla h_j(\bar{x})^\top d = 0,~    \nabla g_i(\bar{x})^\top d \le 0,~ i \in A(\bar{x}) }$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以证明，对于局部最优解，有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theorem 1:&lt;/strong&gt; $D(\bar{x},S)\cap F_{\bar{x},S} =\Omega(\bar{x},f) \cap F(\bar{x},S)=\phi$ （证略，反证法易证)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;切锥&amp;#x26;&amp;#x26;LICQ条件&lt;/h2&gt;
&lt;p&gt;但是这样定义的可行方向集中，如果我们有等式约束，那么可行方向中能使用连续的一条”线段“去刻画可能的点，只存在** 一条弯曲的线**，因此改进可行方向集合的定义方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;切锥：&lt;/strong&gt; 我们称方向  $d \in \mathbb{R}^n$  属于可行点  $x \in S$  处的切维，如果存在序列  ${x_i} \subset S$ ，和实数序列  $\tau_i \searrow 0$ ，使得&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ \frac{x_i - x}{\tau_i} \to d, \quad i \to \infty.  $&lt;/p&gt;
&lt;p&gt;记其切锥集合为  $ T(x, S) := \left{d : \exists \tau_i \searrow 0, {x_i} \subset S, x_i \to x, \quad \text{s.t.} \quad \frac{x_i - x}{\tau_i} \to d\right}. $&lt;/p&gt;
&lt;p&gt;进一步的，我们将S分成不等式约束以及等式约束两部分，有 $T(x,g_i),T(x,h_i)$ 于是有 $T(x,S)=T(x,g_i)\cap T(x,h_i)$&lt;/p&gt;
&lt;p&gt;可以类似证明， $T(x,g_i)\cap T(x,h_i) \cap \Omega(\bar{x},f) =\phi$&lt;/p&gt;
&lt;p&gt;对于这两个可行方向集合的讨论,同样考虑对于可微时，如果我们只考虑&lt;strong&gt;切线方向&lt;/strong&gt; 有，&lt;/p&gt;
&lt;p&gt;使用Taylor展开，有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于等式约束  $\mathcal{E} := {h_i(\bar{x}) = 0, i = 1, ..., \ell}$ ，若  $d \in T(\bar{x}, h)$ ，这里  $T(\bar{x}, h)$  表示  $h_i(\bar{x}) = 0, i = 1, ..., \ell$  的切锥，则存在序列  ${x_k} \subset \mathcal{E}$ ， $\tau_k \searrow 0$ ，且  $x_k \to \bar{x}$  使得  $\frac{x_k - \bar{x}}{\tau_k} \to d$ 。令  $d_k = \frac{x_k - \bar{x}}{\tau_k}$ ，则  $ \nabla h_i(\bar{x})^T d = h_i(\bar{x}; d) = \lim_{k \to \infty} \frac{h_i(\bar{x} + \tau_k d_k) - h_i(\bar{x})}{\tau_k} = 0.  $&lt;/li&gt;
&lt;li&gt;_同理，对于不等式积极约束集 (active set)，记  $\mathcal{A}(\bar{x}) = {i \mid g_i(\bar{x}) = 0, i \in {1, \cdots, m}}$ ，_  $\nabla g_i(\bar{x})^T d = g_i(\bar{x}; d) = \lim_{k \to \infty} \frac{g_i(\bar{x} + \tau_k d_k) - g_i(\bar{x})}{\tau_k} \geq 0, i \in \mathcal{A}(\bar{x}).  $&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此我们有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;等式的线性可行锥方向&lt;/strong&gt; ： $L(\bar{x}, h) := {\mathbf{d} \mid \nabla h_j(\bar{x})^T \mathbf{d} = 0, j = 1, \cdots, \ell}. $&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不等式的线性可行锥方向&lt;/strong&gt; : $L(\bar{x}, g) := {\mathbf{d} \mid \nabla g_i(\bar{x})^T \mathbf{d} \geq 0, i \in \mathcal{A}(\bar{x})}.$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于线性可行锥的方向是容易刻画的，我们猜想，&lt;strong&gt;什么时候可以用切线的约束代替切锥约束呢&lt;/strong&gt; ，从而可以用更简单的方式刻画&lt;strong&gt;全局最优解&lt;/strong&gt; ，从而有以下条件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MFCQ条件&lt;/strong&gt; ：所有的等式约束梯度线性无关，且存在方向d满足 $\nabla h_j(x^&lt;em&gt;)^\top d = 0, \quad \nabla g_i(x^&lt;/em&gt;)^\top d &amp;#x3C; 0, \forall i \in \mathcal{A}(x^*).$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LICQ条件：&lt;/strong&gt; 所有的约束条件的梯度线性无关&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以证明，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theorem 2&lt;/strong&gt; :在&lt;strong&gt;LICQ或MFCQ&lt;/strong&gt; 条件下，有 $L(\bar{x},h)\cap L(\bar{x},g)=T(\bar{x},g)\cap T(\bar{x},h)$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;于是有在LICQ/MFCQ条件下，有 $L(x,g_i)\cap L(x,h_i) \cap \Omega(\bar{x},f) =\phi$ ,成功的给出&lt;strong&gt;局部最优解&lt;/strong&gt; 的合理的刻画&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_01.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;KKT条件推导&lt;/h2&gt;
&lt;p&gt;在证明KKT条件之前我们有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lemma 1&lt;/strong&gt; ：如果 $\bar{x}$ 为原问题的局部最优解，且f,g,h可微，满足MFCQ条件，则有 $D(\bar{x},f)\cap F_{\bar{x},g}\cap L(\bar{x},h)=\phi$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fritz-John条件&lt;/strong&gt; ：若f,g,h可微， $\bar{x}$ 为局部最优解，则存在不全为0的数 $\lambda_0,\lambda_i,i\in\mathcal{A}(\bar{x})$ 以及 $\mu_j,j=1,2,...l$ 使得&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ \lambda_0 \nabla f(\bar{x}) - \sum_{i=1}^{m} \lambda_i \nabla g_i(\bar{x}) - \sum_{j=1}^{\ell} \mu_j \nabla h_j(\bar{x}) = 0,\lambda_i\geq 0 $&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;证明：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_02.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;利用 $\lambda_0!=0$ ,可以左右同时除以 $\lambda_0$ ,同时加上lagrange函数定义以及约束条件 $\lambda_i\geq 0,g_i(\bar{x})\geq 0(i\in \mathcal{A}),h_j(\bar{x})=0$ ,最后对于 $i!\in\mathcal{A}时，\lambda_i=0$ ,有** 我们的KKT条件**&lt;/p&gt;
&lt;p&gt;** KKT条件**：若  $\bar{x}$  为问题局部最优解，且  $\bar{x}$  处满足 LICQ 条件。此时，** 一阶必要条件**可表达为&lt;/p&gt;
&lt;p&gt;$ (\text{KKT}) \begin{cases} \text{稳定性条件} &amp;#x26; \nabla_x \mathcal{L}(\bar{x}, \lambda, \mu) = 0 \ \text{原始可行性条件} &amp;#x26; g_i(\bar{x}) \geq 0, i = 1, \cdots, m; h_j(\bar{x}) = 0, j = 1, \cdots, \ell. \ \text{互补松驰条件} &amp;#x26; \lambda_i g_i(\bar{x}) = 0, i = 1, \cdots, m \ \text{对偶可行性条件} &amp;#x26; \lambda_i \geq 0, i = 1, \cdots, m \end{cases} $&lt;/p&gt;
&lt;h2&gt;局部最优解判定条件&lt;/h2&gt;
&lt;p&gt;模仿我们使用二阶导数判断** 函数的极值点**的方法，我们有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;临界锥&lt;/strong&gt; ：如果 $(x^&lt;em&gt;,\lambda^&lt;/em&gt;,\mu^&lt;em&gt;)$ 为满足KKT条件的对子，有临界锥为 $C(x^&lt;/em&gt;, \lambda^&lt;em&gt;, \mu^&lt;/em&gt;) = {d \in L(x^&lt;em&gt;, S) \mid \nabla g_i(x^&lt;/em&gt;)^T d = 0, \forall i \in \mathcal{A}(x^&lt;em&gt;) \text{且} \lambda_i^&lt;/em&gt; &gt; 0}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;沿着临界锥进行优化，所有的等式约束和不等式约束会保持不变，而对此产生的可行方向d可以导出&lt;strong&gt;局部最优解判定条件&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;必要性&lt;/strong&gt; ：若 $x^&lt;em&gt;$ 为一个局部最优解， $(x^&lt;/em&gt;,\lambda^&lt;em&gt;,\mu^&lt;/em&gt;)$ 满足KKT条件，则 $d^T \nabla_{xx}^2 L(x^&lt;em&gt;, \lambda^&lt;/em&gt;, \mu^&lt;em&gt;) d \geq 0, \quad \forall d \in C(x^&lt;/em&gt;, \lambda^&lt;em&gt;, \mu^&lt;/em&gt;).$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;充分性&lt;/strong&gt; ：若 $d^T \nabla_{xx}^2 L(x^&lt;em&gt;, \lambda^&lt;/em&gt;, \mu^&lt;em&gt;) d &gt; 0, \quad \forall d \in C(x^&lt;/em&gt;, \lambda^&lt;em&gt;, \mu^&lt;/em&gt;).$ 严格成立，那么 $x^*$ 为严格的局部最优解&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个使用以上方法解题的例子&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/image_03.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;以上时线性规划问题求解局部最优解的案例，主要是&lt;strong&gt;通过研究可行方向性质并且于下降方向结合&lt;/strong&gt; ，最后得到KKT条件并使用Hessian矩阵求解的方法。&lt;/p&gt;</content:encoded><h:img src="/_astro/titan5.wO205hmW.jpg"/><enclosure url="/_astro/titan5.wO205hmW.jpg"/></item></channel></rss>