math: true title: “[VeRL] Multi-Turn RL训练源码走读(1)” date: 2025-08-03T15:30:12+08:00 tags: [“framework”,“verl”,“sglang”] series: [“verl”] —math: true 该part主要聚焦相关模块初始化部分 还是以 verl 出发,分析其 end to end mutli-turn RL 训练的全过程。整体上,我希望覆盖所有重要的 class 以及函数,更细粒度的代码不再展开。 为了前后内容的一致性,基于 76f63cffa5 的 commit 进行分析。 虽然本文以分析 verl 的代码为主,写完之后我才意识到,系统设计问题是非常通用的。诸如“log probs 重计算”,“Rollout Engine 显存管理”等等系统设计,是各大 RL 框架都需要考虑的核心问题。 此外因为最近在学习SGLang的实现,本文的推理后端选择的是SGLang展开分析。 —math: true 整个训练的示意图如下,我们会具体展开每个部分。 flowchart LR subgraph W2["Initialize"] WP[Process Data] --> A direction TB D1[Data Prepare] --> A A[TaskRunner] --> B1[RayPPOTrainer] B1 --> Workers subgraph Workers["Workers"] direction TB WA[ActorRolloutWorker] --> WD[FSDP Engine] WB[CriticWorker] --> WD WC[RewardModelWorker] --> WD WD --> WE[SGLang Engine] end Workers --> C1[Hybrid Engine] end subgraph W3["Train Loop"] direction TB E[DataLoader] --> RolloutBox subgraph RolloutBox["Rollout"] F1[Prepare Data] --> F2[SGLang Async Rollout] F2 --> F3[Multi-turn Chat Process] end RolloutBox --> ExpBox subgraph ExpBox["Make Experience"] G1[Recompute Log Probs] --> G2[Compute Reward] G2 --> G3[Compute Advantage] end ExpBox --> UpdateBox subgraph UpdateBox["Train The Model"] H1[Load FSDP Model Weight] --> H2[Compute Gradient] H2 --> H3[Weights Update] H3 --> H4[Sync Weights] end UpdateBox --> E end W2 --> W3 数据预处理 以 GSM8K 为例,预处理脚本是 examples/data_preprocess/gsm8k_multiturn_w_tool.py。整个脚本只做了经典的 huggingface datasets mapping,核心逻辑如下: ...

27 min · 5620 words · Me

math: true title: “[AIInfra] FlashAttention 深度解析:从数学原理到工程实现” date: 2025-09-15T11:30:12+08:00 tags: [“flashattention”] series: [“aiinfra”] —math: true 本文从数学原理出发,深入分析FlashAttention的核心思想、算法设计和各版本演进,通过详实的数学推导、直观的流程图表和具体的数值示例,帮助读者真正掌握这一革命性的Attention优化技术。 —math: true 1. 问题的本质:传统Attention的根本瓶颈 1.1 传统Attention机制的计算模式 传统的Self-Attention机制遵循如下计算流程: $$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V $$让我们用具体数值来理解这个过程的复杂性: 示例场景:考虑一个典型的语言模型场景 序列长度:$n = 2048$(如GPT-2的上下文长度) 特征维度:$d_k = 64$(每个attention head的维度) 输入张量形状:$Q, K, V \in \mathbb{R}^{2048 \times 64}$ 第一步:计算注意力得分矩阵 $$S = \frac{QK^T}{\sqrt{d_k}} \in \mathbb{R}^{2048 \times 2048}$$这一步产生了一个 $2048 \times 2048 = 4,194,304$ 个元素的矩阵,以FP16精度存储需要约8MB内存。 第二步:Softmax归一化 $$P = \text{softmax}(S) \in \mathbb{R}^{2048 \times 2048}$$Softmax计算需要: 计算每行的最大值:$m_i = \max_j S_{i,j}$ 计算指数和:$l_i = \sum_j e^{S_{i,j} - m_i}$ 归一化:$P_{i,j} = \frac{e^{S_{i,j} - m_i}}{l_i}$ 这又需要存储另一个 $2048 \times 2048$ 的矩阵。 ...

10 min · 1993 words · Me

math: true title: “Docker Fundamentals: Namespace” date: 2021-04-01T11:22:18+08:00 hero: /images/posts/k8s-docker.jpg menu: sidebar: name: Docker Fundamentals (Namespace) identifier: docker-namespace parent: cloud-computing weight: 10 draft: false —math: true 容器技术出现已经很久,只不过Docker容器平台的出现它变火了。Docker是第一个让容器能在不同机器之间移植的系统,它简化了打包应用的流程,也简化了打包应用的库和各种依赖。思考下整个OS的file system能直接被打包成一个简单的可移植的包,一开始的时候概念上还是很有趣的。 有时候我认为自己的阅读比较碎片化(short-term memory越来越少),所以我想把之前学习容器知识的一些基础技术再整理出来,也算是给自己学习的反馈。这个基础系列从Linux Namespace开始,后续会陆续介绍比如cgroup、aufs、devicemapper等技术。 参考 Namespace in operation Linux namespace man page Introduction to linux namespace 什么是Namespace 简单来说,linux namespace是Linux提供的一种内核级别环境隔离的方法。在早期的Unix中,提供了一种叫做chroot的系统调用:通过修改root目录把用户关到一个特定的目录下面。这种就是简单的隔离方式,也就是chroot内部的file system无法访问外部的内容。Linux Namespace在此基础之上,提供了对UTS、IPC、mount、network、PID、User等隔离机制。 这里可以简单举例,比如Linux的超级父进程的PID为1,如果我们可以把用户的进程空间关到某个进程分支之下,并且像chroot那样能够让下面的进程看到那个超级父进程的PID为1,而不同PID Namespace中的进程无法看到彼此,这样就能达到进程隔离。 Linux Namespace有以下的种类,供给后续参考(刚看有个印象就行): 分类 系统调用参数 相关内核版本 Mount namespaces CLONE_NEWNS Linux 2.4.19 UTS namespaces CLONE_NEWUTS Linux 2.6.19 IPC namespaces CLONE_NEWIPC Linux 2.6.19 PID namespaces CLONE_NEWPID Linux 2.6.24 Network namespaces CLONE_NEWNET 始于Linux 2.6.24 完成于 Linux 2.6.29 User namespaces CLONE_NEWUSER 始于 Linux 2.6.23 完成于 Linux 3.8) 其主要涉及到三个系统调用: ...

11 min · 2323 words · Me