Arganzheng's Blog

stay hungry, stay foolish

LoRA 专题(01):低秩假设:为什么两个瘦矩阵够用,以及它省了哪几本账

LoRA 01: The Low-Rank Hypothesis — Why Two Thin Matrices Suffice, and Exactly What They Save

更新 @2026-09-30:实验用 peft 0.21.1、trl 1.14.1、transformers 5.17.0、PyTorch 2.14(CPU,8 线程),模型 Qwen2.5-0.5B(base),数据 no_robots。配套脚本 ai-learning-labs/lora/01_low_rank.py(子实验 hand / account / speed / init / spectrum);正文给出理解所需的全部数字。 LoRA 的全部内容是一句话:冻结 \(W\),只训一对瘦矩阵 \(B\)、\(A\),让 \(W' = W + \frac{\alpha}{r} BA\)。这一句里有三个不显然的地方:为什么改动可以只有秩 \(r\)...

LoRA 专题:SFT 的默认微调方式,从低秩假设到多租户服务(总纲)

LoRA, the Default Way to Fine-Tune: From the Low-Rank Hypothesis to Multi-Tenant Serving — Series Overview

更新 @2026-09-30:本系列的实验用 peft 0.21.1、trl 1.14.1、transformers 5.17.0、bitsandbytes 0.50.2、PyTorch 2.14(CPU),模型是本地缓存的 Qwen2.5-0.5B,数据是 HuggingFaceH4/no_robots。文中的参数名(r、lora_alpha、target_modules、use_rslora、init_lora_weights……)以这组版本为准;LoRA 的数学与账目不随版本变。 内容简介 《LoRA 专题》是一组共三篇正文加一篇总结的系列文章,是《AI 算法工程师学习地图》 L5 后训练层的专题篇。LoRA(Low-Rank Adaptation...

读 Hugging Face 源码(05):系列总结与通关自测

Reading the Hugging Face Source: Series Recap and Final Self-Test

四篇正文回答了一个问题:工具箱第五篇那六行代码,执行时各经过哪些文件的哪些函数。第一篇读模型的加载与一次前向,第二篇读 generate 的循环,第三篇读文本与数据两条流水线,第四篇读 LoRA 怎么挂上去与三种 loss 各在哪一行。本文把四篇压成一张「问题 → 文件 → 函数」的索引表,拎出贯穿五个库的四条设计线,再给一套自测。 读完这四篇,你应该能回答哪些问题?1 哪些文件名、函数名与数字必须能脱口而出?2 怎么判断自己是”读过”还是”掌握”了?3 先把整个系列放在一张图上——箭头是调用或数据上的依赖,不是阅读顺序: %%{init: {"flowchart": {"wrappingWidth": 230}}}%% %% 图:四篇的依赖:03 造...

读 Hugging Face 源码(04):peft 与 trl——LoRA 怎么挂上去,SFT / DPO / GRPO 的 loss 各在哪一行

Inside peft and trl: get_peft_model, the LoRA Linear, SFT Labels and Packing, dpo_loss and GRPO Advantages

更新 @2026-09-30:本文对着 peft 0.21.0(tuners/lora/layer.py 2739 行、tuners/tuners_utils.py 2781 行)与 trl 1.13.0(trainer/sft_trainer.py 1927 行、dpo_trainer.py 1823 行、grpo_trainer.py 3497 行)读,配套脚本在 ai-learning-labs/hf-source-reading/,模型用本地缓存的 Qwen2.5-0.5B。trl 是 Hugging Face 几个库里改得最快的一个(一年三十多个版本,SFTTrainer 的数据契约改过数次),路径与名字以 1.13.0 为准,不引用行号;读别的版本...

读 Hugging Face 源码(03):tokenizers 与 datasets——从 messages 到 input_ids,从 Arrow 文件到 collate_fn

Inside tokenizers and datasets: the Rust Pipeline, Chat Templates, Arrow Tables, map and Fingerprints

更新 @2026-09-30:本文对着 tokenizers 0.23.2(Rust 库 + Python 绑定)、transformers 5.17.0 的 tokenization_utils_base.py / tokenization_utils_tokenizers.py / utils/chat_template_utils.py、datasets 5.0.1 的 arrow_dataset.py(7417 行)/ load.py / builder.py / iterable_dataset.py 读,配套脚本在 ai-learning-labs/hf-source-reading/,用本地缓存的 Qwen2.5-0.5B tokenizer 与...

读 Hugging Face 源码(02):generate——一次采样的完整调用链

Inside transformers, Part 2: generate, GenerationConfig, LogitsProcessors, StoppingCriteria and the Decode Loop

更新 @2026-09-30:本文对着 transformers 5.17.0 的 generation/ 目录读(utils.py 4250 行、logits_process.py 3222 行、stopping_criteria.py 643 行、configuration_utils.py 1892 行),配套脚本在 ai-learning-labs/hf-source-reading/,模型用本地缓存的 Qwen2.5-0.5B。路径与名字以该版本为准,不引用行号。 上一篇的前向在 logits 处结束:[B, T, 151936] 个分数。推理时接下来的每一件事——把最后一个位置的分数变成一个 token、把它拼回去、再前向一次——都在 mode...

读 Hugging Face 源码(01):transformers 模型侧——from_pretrained 怎么把三个文件变成 nn.Module,forward 怎么走到 loss

Inside transformers, Part 1: from_pretrained, the Decoder Stack, Attention Dispatch, KV Cache and the Loss

更新 @2026-09-30:本文对着 transformers 5.17.0(2026-09-09 发布)的源码读,配套脚本在 ai-learning-labs/hf-source-reading/,模型用本地缓存的 Qwen2.5-0.5B。文中的文件路径、类名、函数名以该版本为准,不引用行号;transformers 的目录结构改得很快,读别的版本时请以本地源码对照——找入口的方法不变。 工具箱第五篇用六行代码组装了一次 LoRA SFT,第一行就是 AutoModelForCausalLM.from_pretrained(name)。那一篇把它当黑盒:进去一个 Hub 名字,出来一个 nn.Module。这一篇把黑盒打开:这个函数怎么根据 conf...

读 Hugging Face 源码:从 from_pretrained 到 GRPO 的 loss(总纲)

Reading the Hugging Face Source: transformers, tokenizers, datasets, peft and trl, One Call Chain at a Time

更新 @2026-09-30:本系列对着 transformers 5.17.0(2026-09-09 发布)、tokenizers 0.23.2、datasets 5.0.1、peft 0.21.0、trl 1.13.0 的源码读,模型用本地缓存的 Qwen2.5-0.5B。文中的文件路径、类名、函数名以这组版本为准,不引用行号;读别的版本请以本地源码对照——找入口的方法不变。 内容简介 《读 Hugging Face 源码》是一组共四篇的系列文章,是《AI 算法工程师学习地图》 L4–L5 两层的深入篇。工具箱第五篇用六行代码组装了一次 LoRA SFT,并在末尾说「读源码是最快的路」,列了六个入口;读者问:既然代码量不大,能不能把这几个入口真的读一...

GPU Kernel 工程(11):系列总结与通关自测

GPU Kernel Engineering: Series Recap and Final Self-Test

十篇正文回答了一个问题:一个 kernel 为什么快、为什么慢,以及如何把它写到接近硬件极限。第一篇把 GPU 拆开并建立 Roofline,第二篇写出第一个 kernel 并学会测量,第三、四篇把 memory-bound 的 elementwise 与 reduction 推到带宽墙,第五、六篇把 GEMM 从 naive 推到 Tensor Core,第七篇用 Triton 看编译器接管了哪一层,第八、九篇把这些工具用到 attention、量化与融合 kernel 上组装出一个 decoder layer,第十篇讲怎么剖析、测试、接入框架并合入一个 PR。 本文不讲新内容,做三件事:把十篇压成一张表与十段回顾,把贯穿全系列的几条线拎出来,然后给一套三段式的...

GPU Kernel 工程(10):剖析、测试与贡献——把 kernel 做成产品

Profiling, Testing and Contributing: Turning a Kernel into a Product

前九篇结束时,手上有一个用自己写的 kernel 跑通的 decoder layer 前向:RMSNorm、RoPE、BF16 Tensor Core GEMM、FlashAttention 前向、SiLU-mul、fused residual+RMSNorm、INT4 weight-only GEMM。它们能跑、结果和 PyTorch eager 对得上、每一个都在自己的 benchmark 里比 naive 版本快很多。 但”能跑”和”能合入”之间还有一整段工程。一个 kernel 要成为别人敢用的东西,需要回答四个问题:它到底卡在哪里(剖析);它在所有会遇到的输入上都对(测试);它确实比原来快、而且以后不会悄悄变慢(benchmark);它在别人的 GPU ...

×