Fanyi's Blog


108 posts1–10 · Page 1 of 11
刷 xhs 看到的题
刷 xhs 刷到学弟的一个题,就写了一下。xhs 连接 给你一根长度为 \(s\) 的绳子,以及两面夹角为 \(\theta\) 的墙。借助墙作为边界,最多能围出多大面积?如果两面墙不再无限长,而是长度分别为 \(x,y\) 的线段,答案又会怎样变化? 两面墙在墙角 \(O\) 相交,夹角满足 \(0<\theta<\pi\),角度用弧度表示。绳长 \(s>0\) 固定,绳子柔软、不可伸长,可以弯曲,也可以自由选择形状。 将绳子的两个端点分别系在两面墙上的 \(A,B\),让绳子与墙段 \(OA,OB\) 组成一个简单闭合边界。系绳点可以沿墙移动,绳子不能自交;墙段不消耗绳长。 分别考虑三种情况: 两种有限墙模型都允许区域伸到原来夹角之外,并始终要求绳子与 \(OA,OB\) 组成不自交的闭合边界。 求能够围出的最大面积,以及达到这个面积时的绳子形状和系绳点位置。 允许 \(A\) 或…
Great Ideas in Rust
程序读入一行 alice,42,把它解析成名字和分数,再交给后台任务处理。这几步很简单,但数据在其中经历了几次交接:解析出的名字可以直接引用原来的文本吗?读取下一行时,输入缓冲区能否复用?如果后台任务还没结束,谁负责保留它需要的数据? Rust 把这些关系放进了类型和函数接口。一个函数可以临时借用文本,也可以接管它;解析结果可以依赖输入,也可以拥有独立的存储。这些选择决定了数据能够怎样流动,编译器则检查每一次使用是否遵守约定。 假设程序读到一行文本,准备把它放进待处理任务。Python 或 Java 中,两次赋值通常意味着两个名字引用同一个对象;C++ 的 std::string 赋值通常产生独立副本,也可以显式 move。Rust 需要让“谁最终释放字符串的缓冲区”保持明确,于是对 String 这样的类型,按值赋值默认转移 ownership: 这里没有复制一份字符串内容。queued…
Computer Networks: Architecture and Routing
一台电脑要把文件交给远处的服务器,最直接的办法是拉一根线。但如果每两台机器都要单独连接,\(n\) 台机器就需要 \(\frac{n(n-1)}{2}\) 条链路;如果所有机器共用一根线,它们又只能争抢同一份容量。我们需要一些中间节点,让许多通信复用同一张网络,同时还能在链路故障后换条路走。 这就引出了计算机网络的几个核心问题:数据怎样被拆开和转发?共享资源不足时怎么办?每个节点只知道局部信息,怎样共同找到一条正确的路径?当网络规模继续增长,又怎样避免每台路由器都记住每台机器? 这是 CS Revisited / Computer Networks 的第一篇。Computer Networks 会按主题持续分篇,本篇先建立架构与路由的基础。假设读者熟悉基本的数据结构、图和概率;协议术语会在用到时引入。本文覆盖 Berkeley CS 168 (UC Berkeley CS 168,…
现代通信协议:从可靠传输到实时媒体与消息语义
假设我们正在做一个在线白板:打开页面后,两个人可以一起画图、移动光标、语音交流,还能上传文件。画完的内容需要保存到服务器。 这些数据都经过网络,但它们对网络的要求并不相同。 上传文件时,少一个字节都不行,慢一点通常可以接受。移动光标时,新的位置已经到了,半秒前的位置反而没有必要补回来。语音也有时效性,但丢掉一段声音后,还需要决定怎样维持连续播放。保存白板时,即使所有请求字节都成功发送,也不代表服务器已经把修改写进数据库。 因此,“选一个更快的协议”还不是一个足够明确的问题。我们要先问:哪些数据必须完整?哪些数据过时就可以丢弃?收到什么,才算事情完成? 本文沿着这三个问题展开:先从 TCP 的可靠传输走到 QUIC 和 HTTP/3,再解释实时通信为什么需要 WebRTC、WebTransport 这样的接口,最后讨论 gRPC、MQTT、DDS 和 CoAP 如何表达应用真正关心的操作与…
多媒体压缩:用同一条主线理解图像、音频与视频
一张 \(4000\times3000\)、每通道 8 bit 的 RGB 照片若直接保存像素,需要 36 MB。一分钟 44.1 kHz、16-bit、双声道 PCM 音频约需 10.6 MB。一段 \(1920\times1080\)、30 fps、每像素 24 bit 的原始视频,码率更达到约 1.49 Gbit/s。三者看似是不同问题,其实都在问同一件事:decoder 已经能从哪些结构猜到当前 sample,又该把有限的 bits 花在哪些猜不准且重要的误差上? 把图像、音频和视频放在一起讨论,传统信号处理里更常称为 multimedia compression(多媒体压缩)。近年的「multimodal compression(多模态压缩)」还常指联合压缩文字、视觉、语音等模型表示,目标可能是保留语义而不是还原媒体 sample。本文讨论前一种问题;最后再说明学习式 codec…
Vision Transformer:从图像 Patch 到多模态模型
给模型一张菜单,问它「第二行的价格是多少」,模型需要先保留小字,再找到第二行,最后把数字读出来。如果预处理已经把字缩成模糊的一团,后面的语言模型再大,也无法从图像中找回被丢掉的笔画。视觉模型的设计,首先是在决定保留哪些信息、让哪些区域交换信息,以及把多少信息交给下游。 Vision Transformer(ViT)把图像切成 patch,用 Transformer 在这些 patch 之间交换信息。今天许多多模态模型仍沿用这个骨架,但在分辨率、位置编码、预训练和输出压缩上有不同选择。本文先从输入推导基本 ViT,再沿着这些选择理解实际模型。Attention 的更多变体见这一篇,视觉自监督目标见 SSL。 模型部分按 2026-09-22 可核对的论文、官方权重配置与实现展开,覆盖常见视觉 backbone、多模态模型,以及能说明不同设计方向的公开 encoder。公开权重不等于公开完整…
让 AI 来做一道我以前出的题:矩阵行列去重
很久以前,我自己想过这样一道题,记在洛谷里,没有公开。当时题面已经想好了,但我其实也不太会做,更没有确定应该把数据范围开到多少。 今天忽然想起来,现在 AI 已经这么厉害了,不如把这道题拿出来,看看能不能让 AI 解决一下。 所以先说明一下:题目是我以前想的;这篇 blog 的解题思路、推导、代码和文字整理,全部由 AI 生成。 我提出的问题很简单:能不能做到 \(\mathcal{O}(nm)\)?实在不行,有没有比暴力好一些的方法? 这次得到的结果是:有一个可以直接实现的轻重分治加 bitset 解法,也可以借助快速矩阵乘法得到更好的理论上界。至于最想要的线性算法,目前还没有找到。不过,这个目标和 0/1 矩阵乘法之间有一个很直接的联系。 给定一个 \(n\times m\) 的矩阵 \(a\),输出一个同样大小的矩阵 \(b\),其中 也就是把第 \(i\) 行和第 \(j\) 列放…
Self-Supervised Learning
给一张照片标上「猫」,是人在提供监督信号。但即使没有这个标签,我们仍然知道:同一张照片的两个裁剪来自同一个场景,被遮住的区域与周围内容有关,一段视频的前后帧通常描述同一个过程。Self-supervised learning 利用数据内部的关系构造训练任务,再把学到的表征用于其他任务。 这里的 SSL 指 self-supervised learning。这个缩写也常用于 semi-supervised learning,后者通常指同时利用有标签与无标签数据。本文主要讨论视觉表征;语言模型的 next-token prediction 也属于自监督任务,但不在这里展开。 设图像为 \(x\),encoder 为 \(f_\theta\),我们希望得到有用的表征 \(h=f_\theta(x)\)。预训练时,模型可能在判断两个裁剪是否来自同一张图,也可能在预测被遮住的 patch。部署时,…
Infra: Flash Attention
Attention 的公式很短。先只看一个 head,忽略 batch,并让 query、key、value 的维度都为 \(d\): Softmax 沿每一行进行。\(S_{ij}\) 是第 \(i\) 个 query 对第 \(j\) 个 key 的 score,\(P_{ij}\) 是归一化后的权重;输出 \(O_i\) 是所有 value 的加权和。 直接按公式调用三个算子,会先得到完整的 \(S\),再得到完整的 \(P\),最后计算 \(O\)。两个中间矩阵都是 \(N\times N\),但调用者通常只需要 \(N\times d\) 的输出。必须计算每一对 query 和 key 的关系,是否就意味着必须同时保存所有关系? FlashAttention (Dao et al., 2022) 从这里入手:让一小块 score 在 GPU 片上产生、参与 softmax 和加权…
Muon
如果第一次听说 Muon,可以先把它理解成一种专门处理神经网络二维权重矩阵的 optimizer (Jordan et al., 2024)。它不改变模型结构、loss 或 backpropagation;forward 和 backward 仍然照常进行。改变的是 backward 之后的 optimizer step:算出的梯度最终怎样变成权重更新。 但梯度本身还没有完整回答“应该走哪一步”。它能用一阶近似比较不同更新谁更可能降低 loss,却没有规定多大的更新才算同样大。对向量参数,我们常把 Euclidean norm 当作默认尺度;对 linear layer 的矩阵 \(W\),还可以直接关心它作为映射 \(y=Wx\) 时,一步更新最多会让输出特征改变多少。选择不同的尺度,就会设计出不同的 optimizer。 因此本文不从背诵 Muon 的流程开始,而是假设我们正在自己设计…