Arganzheng's Blog

stay hungry, stay foolish

读 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 ...

GPU Kernel 工程(09):量化与融合 kernel——推理系统的其余部分

Quantized and Fused Kernels: The Rest of the Inference Stack

上一篇把 attention 讨论完了。一个 decoder layer 里除了 attention 和标准 GEMM,剩下的是一堆”小 kernel”:RMSNorm、RoPE、SiLU-mul、把 KV 写进分页 cache、把权重从 INT4 解开、把激活压成 FP8、MoE 的 token 重排、采样。它们单个都不复杂,但数量多、变化快,加起来占掉推理时间的一个可观比例——而且是 vLLM、SGLang 这些项目里 PR 最活跃的区域。 这一篇把它们放在同一个方法论下过一遍:先算这个 kernel 理论上要搬多少字节、做多少 FLOPs,再看实现,再解释差距。核心问题是总纲提出的那个: 一个 INT4 weight-only GEMM,decode...

GPU Kernel 工程(08):Attention Kernel——FlashAttention 与 PagedAttention

Attention Kernels: FlashAttention and PagedAttention from Derivation to Code

前七篇分别处理了 GPU 的硬件结构与 Roofline、CUDA 执行模型、访存合并、shared memory 与 reduction(其中包括 online softmax)、GEMM 的分块、Tensor Core 与 CUTLASS、Triton。这一篇是它们的汇合点:attention 同时包含两个 GEMM(\(QK^T\) 与 \(PV\))、一个逐行的 reduction(softmax),以及推理时特有的内存访问模式(分页的 KV cache)。它是 Transformer 推理里最重要、也最难写好的 kernel。 总纲给这一篇提的核心问题是: 一个序列长度 4k、head dim 128 的 attention,标准实现和 Flas...

GPU Kernel 工程(07):Triton——块级编程与编译器的边界

Triton: Block-Level Programming and Where the Compiler Stops

前六篇一直在 CUDA 的世界里:每个线程算什么、warp 怎么合并访存、shared memory 怎么分块、mma.sync 怎么喂 fragment。到了第六篇,一个能跑到 cuBLAS 七八成性能的 BF16 GEMM 已经是两三百行代码,而且每一行都有”为什么这样写”的理由——tile 尺寸、bank conflict 的 padding、cp.async 的 stage 数、寄存器分块的形状。 这一篇换一种写法。Triton 把”线程”从编程模型中拿掉:程序员以 block 为单位思考,写的是”这个 block 加载哪一块数据、做什么张量运算、存到哪里”,而线程到元素的映射、shared memory 的分配、向量化、软件流水、mma 指令的选择,全部...

×