Skip to content

Commit

Permalink
add ml
Browse files Browse the repository at this point in the history
  • Loading branch information
liqiankun1111 committed Nov 15, 2024
1 parent ebfa342 commit cea3a66
Show file tree
Hide file tree
Showing 22 changed files with 132 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,11 @@ func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framewor
return nil
}
```

## 其它
[6 张图带你深入了解 kube-scheduler](https://mp.weixin.qq.com/s/2elOZD0yaBf-WvMCSD5zHQ)Scheduler 的作用是 负责将 Pod 调度到 Node 上。如果让你设计这个组件,你会如何设计,保证它稳定高效的运行。
1. 需要能够实时监听到 有新的 Pod 待调度
2. 同一时间如果有大量待调度的 Pod,如果处理,如何保证不能漏掉,应该先处理哪个 Pod,调度过程中,如果失败,如何处理。所以得加个队列,有重试机制等
3. 调度过程中依赖 Node、Pod 的实时信息,根据 Node、Pod 信息,决策 Pod 调度到哪个Node上合适,每次调度 调 Apiserver ,显然低效, 得在本地缓存一份数据,加个缓存
4. 调度选择过程中,考虑因素太多,很难周全,可扩展性一定要设计好
5. Pod 绑定过程中 可能依赖 pvc 绑定等,耗时较长, 所以绑定得是异步的, 但是匹配哪个Node合适的算法 需要同步执行,所以要有两个周期, 调度周期和绑定周期,调度周期串行,绑定周期并行
9 changes: 5 additions & 4 deletions _posts/Kubernetes/Scheduler/2020-03-21-resource_scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ Kubernetes和Mesos调度的最大区别在于资源调度请求的方式

[揭开阿里巴巴复杂任务资源混合调度技术面纱](https://mp.weixin.qq.com/s/wj0hrHIRHnBUNZZXnRm5xg)

业界系统的调度架构主要分为四类:单体调度、两层调度、共享调度和混合调度。这些调度架构的本质区别其实只有两点:
1. 调度时调度器是否拥有全局的资源视图;
2. 不同的应用是否拥有多个资源调度器。
单体调度顾名思义,即只有一个调度器,调度器拥有全局资源视图的架构,Google Borg 和 K8s 都采用这个架构。单体架构的好处是,所有的任务都由唯一的调度器处理,调度器可以充分的考虑全局的资源使用情况,能方便的做出最优调度。但由于调度架构的限制,集群性能受限于单体的性能,无法支撑过大的集群。两层调度拥有多个调度器,Apache Mesos 和 Hadoop YARN 都采用这个架构。两层调度中,每个应用的调度器首先向中心节点获取资源,再将其分配给应用中的各个任务。两层调度解决了单体调度的性能问题,但是调度器仅拥有局部资源视图,无法做出最优调度。共享调度拥有多个调度器,每个调度器拥有全局资源视图,Omega 采用了这个架构。共享调度方案中,每个调度器都可以并发地从整个资源池中申请资源,解决了性能问题和最优调度问题,且可以支持较大集群。
业界系统的调度架构主要分为四类:单体调度、两层调度、共享调度和混合调度。这些调度架构的本质区别其实只有两点:调度时调度器是否拥有全局的资源视图;不同的应用是否拥有多个资源调度器。
1. 单体调度顾名思义,即只有一个调度器,调度器拥有全局资源视图的架构,Google Borg 和 K8s 都采用这个架构。单体架构的好处是,所有的任务都由唯一的调度器处理,调度器可以充分的考虑全局的资源使用情况,能方便的做出最优调度。但由于调度架构的限制,集群性能受限于单体的性能,无法支撑过大的集群。
2. 两层调度拥有多个调度器,Apache Mesos 和 Hadoop YARN 都采用这个架构。两层调度中,每个应用的调度器首先向中心节点获取资源,再将其分配给应用中的各个任务。两层调度解决了单体调度的性能问题,但是调度器仅拥有局部资源视图,无法做出最优调度。
3. 共享调度拥有多个调度器,每个调度器拥有全局资源视图,Omega 采用了这个架构。共享调度方案中,每个调度器都可以并发地从整个资源池中申请资源,解决了性能问题和最优调度问题,且可以支持较大集群。调度器间资源申请冲突可通过悲观锁或乐观锁来解决。

## 资源调度的复杂性

[没有银弹,只有取舍 - Serverless Kubernetes 的思考与征程(一)](https://mp.weixin.qq.com/s/1aMalQs-AE2L1aA5X20gJA)
Expand Down
16 changes: 10 additions & 6 deletions _posts/MachineLearning/Framework/2023-12-16-llm_inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ LLM推理需要的芯片形态,最重要的是内存带宽和互联带宽,

![](/public/upload/machine/attention_kvcache.png)

在推理的时候transformer本质上只需要计算出$O_i$ ,即一个字一个字地蹦。PS:也回答了为何不缓存Q
在推理的时候transformer本质上只需要计算出$O_i$ ,即一个字一个字地蹦。PS:也回答了为何不缓存Q?每一轮的q都是新的。
1. Attention的第i个输出只和第 i 个query有关,和其他query无关,所以query完全没有必要缓存,每次预测 $O_i$时只要计算最新的$O_i$,其他的丢弃即可。
2. Attention的输出$O_i$的计算和完整的K和V有关,而K、V的历史值只和历史的O有关,和当前的O无关。那么就可以通过缓存历史的K、V,而避免重复计算历史K、V
![](/public/upload/machine/kvcache_no_query.png)
Expand Down Expand Up @@ -236,6 +236,13 @@ System Prompt Caching,也称为 Prefix Sharing,其基本思想是对System P

### Flash Attention


[Flash Attention 的数学原理](https://mp.weixin.qq.com/s/Nv9iS96J7pVZRvH7U8fWsA)**Flash Attention 并没有减少 Attention 的计算量**,也不影响精度,但是却比标准的Attention运算快 2~4 倍的运行速度,减少了 5~20 倍的内存使用量。究竟是怎么实现的呢?简单来说,Flash Attention 让 Attention 的所有计算都符合结合律,这样就可以充分利用 GPU 的并行优势。从Attention 计算公式可以看出,Attention 的并行计算主要解决两个问题:
1. 矩阵的并行计算。$X=QK^T$
2. Softmax 的并行计算。$A=softmax(\frac{X}{\sqrt{d}})$。
矩阵的并行算法已经比较成熟,GPU 上也有 TensorCore 来加速计算。 Softmax 操作让并行计算有些棘手。Softmax 的并行无法将计算放到一个 Kernel 中。后面的建议细读文章。
传统方法计算时,需要引入两个中间矩阵X和A并存在全局内存中。需要先从全局内存中读取矩阵 QK,并将计算好的X写入全局内存。然后从全局内存中读取X,计算Softmax得到矩阵A,再将其写入全局内存,最后读取矩阵A和矩阵V,计算$O=AV$ 计算得到矩阵O,这个过程会极大的占用显存的带宽。Flash Attention 的目标是尽可能使用 SRAM来加快计算速度,避免从全局内存中读取或写入注意力矩阵(H100 全局内存80G,访问速度3.35TB/s,但当全部线程同时访问全局内存时,其平均带宽仍然很低)。达成该目标需要做到在不访问整个输入的情况下计算softmax函数,并且后向传播中不能存储中间注意力矩阵(存部分信息,反向传播时重新计算)。PS:通过数学变换,换个算法,减少内存占用,pytorch2.0 已支持Flash Attention。PS:FA的本质是融合算子的一种新的实现方式。

[图解大模型计算加速系列:Flash Attention V1,从硬件到计算逻辑](https://mp.weixin.qq.com/s/J2i2MDv4us_GMwCyku0tnw)在矩阵分块的时候设计好一个能够充分利用高速访存HBM的分块方法,让一次搬运进HBM中的参数可以全部和该做乘加操作的算子都计算完再丢弃,达到数量单次访存利用率最大化。
1. Fast(with IO-Awareness),计算快。它发现:计算慢的卡点不在运算能力,而是在读写速度上。所以它通过**降低对显存(HBM)的访问次数**来加快整体运算速度(通过分块计算(tiling)和核函数融合(kernel fusion)来降低对显存的访问),这种方法又被称为IO-Awareness。
2. Memory Efficicent,节省显存。在标准attention场景中,forward时我们会计算并保存N*N大小的注意力矩阵;在backward时我们又会读取它做梯度计算,这就给硬件造成了的存储压力。在Flash Attention中,则巧妙避开了这点,使得存储压力降至。在后文中我们会详细看这个trick。
Expand All @@ -245,11 +252,7 @@ System Prompt Caching,也称为 Prefix Sharing,其基本思想是对System P

[图解大模型计算加速系列:Flash Attention V2,从原理到并行计算](https://mp.weixin.qq.com/s/gMRZV-ZCrFccKPKSkOpxsQ) 未读。

[Flash Attention 的数学原理](https://mp.weixin.qq.com/s/Nv9iS96J7pVZRvH7U8fWsA)Flash Attention 并没有减少 Attention 的计算量,也不影响精度,但是却比标准的Attention运算快 2~4 倍的运行速度,减少了 5~20 倍的内存使用量。究竟是怎么实现的呢?简单来说,Flash Attention 让 Attention 的所有计算都符合结合律,这样就可以充分利用 GPU 的并行优势。从Attention 计算公式可以看出,Attention 的并行计算主要解决两个问题:
1. 矩阵的并行计算。$X=QK^T$
2. Softmax 的并行计算。$A=softmax(\frac{X}{\sqrt{d}})$。
矩阵的并行算法已经比较成熟,GPU 上也有 TensorCore 来加速计算。 Softmax 操作让并行计算有些棘手。Softmax 的并行无法将计算放到一个 Kernel 中。后面的建议细读文章。
传统方法计算时,需要引入两个中间矩阵X和A并存在全局内存中。需要先从全局内存中读取矩阵 QK,并将计算好的X写入全局内存。然后从全局内存中读取X,计算Softmax得到矩阵A,再将其写入全局内存,最后读取矩阵A和矩阵V,计算$O=AV$ 计算得到矩阵O,这个过程会极大的占用显存的带宽。Flash Attention 的目标是尽可能使用 SRAM来加快计算速度,避免从全局内存中读取或写入注意力矩阵(H100 全局内存80G,访问速度3.35TB/s,但当全部线程同时访问全局内存时,其平均带宽仍然很低)。达成该目标需要做到在不访问整个输入的情况下计算softmax函数,并且后向传播中不能存储中间注意力矩阵(存部分信息,反向传播时重新计算)。PS:通过数学变换,换个算法,减少内存占用,pytorch2.0 已支持Flash Attention。PS:FA的本质是融合算子的一种新的实现方式。
[FlashAttention算法之美:极简推导版](https://mp.weixin.qq.com/s/hu5D1dmCFkeStxbXBE-czA) 未读。

### 调度优化/动态批处理

Expand Down Expand Up @@ -362,6 +365,7 @@ FasterTransformer 是真对于 Transofrmer 类型模型(也包括 encoder-only
2. 量化对于文本生成特别有效,因为我们关心的是选择 最可能的下一个词元的分布 ,而不真正关心下一个词元的确切 logit 值。所以,只要下一个词元 logit 大小顺序保持相同, argmax 或 topk 操作的结果就会相同。
3. 常用量化方法:GPTQ、AWQ和GGUF
3. 模型稀疏化。模型稀疏化是一种重要的优化方法。它的主要目的是减少模型参数的数量,从而降低模型的复杂度,提高模型的泛化能力和计算效率。模型稀疏化的主要方法有剪枝、量化、低秩近似等。剪枝是一种直接删除模型中部分参数的方法,它可以有效地减少模型的规模,但需要注意不能过度剪枝,以免影响模型的性能。低秩近似则是通过将模型转换为低秩矩阵,来减少模型的参数数量。
4. 推理引擎都是做成多卡TP而不是PP,主要是因为从服务器视角看PP的吞吐上限更高,但是从单个请求视角看TP的延迟会更低,在线服务往往不需要那么高的吞吐,延迟更加重要。后来vLLM还增加了流水线并行(Pipeline Parallelism)的支持,从vLLM版本 0.5.1 开始支持跨多节点的流水线并行,对于那些跨多个节点的超大模型和低带宽连接,流水线并行是一种更优的选择。

## 硬件

Expand Down
8 changes: 6 additions & 2 deletions _posts/MachineLearning/Infra/2021-08-18-gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ keywords: gpu

GPU 的架构;内存管理;任务管理;数据类型。

内存将数据传输到CPU大概每秒大概传输200GB(也就是每秒25G FP64),cpu 计算能力大概是2000 GFLOPs FP64,这两者的比值就是设备的计算强度。也就是cpu 每秒不对一个数据处理80次,cpu 就会空闲,但也没有什么算法需要对一个数据处理80次。当增加FLOPs速度比增加内存带宽的速度快的时候,计算强度就会上升。为什么?物理上光速 3亿米/秒,电脑时钟30亿Hz,在一个时钟周期,光只传播了10cm,电流在硅中的传播速度只有光的五分之一(6万公里/秒),物理实际上很复杂,根据经验,一个时钟周期内,电流的移动只有20mm。
CPU 的期望是一个线程基本完成所有工作,将这些线程从一个切换到另一个是非常昂贵的(上下文切换),cpu设计者把所有资源都投入到延迟上了。GPU 设计师将所有资源的都投入到增加线程中,而不是减少延迟。此外,gpu 使用寄存器缓存来解决高延迟问题,以及通过靠近数据来减少延迟(内存传输数据慢,cpu 没有忙起来,内存也没有忙起来)。gpu 选择增加线程,每个sm2048个线程,一次跑一批(warp)线程,当一些线程因为等待延迟关闭时,其它线程大概已经load好数据了准备运行了。这就是gpu工作的秘密,它可以在不同的warp之间切换,并且在一个时钟周期内完成,所以根本没有上下文开销。gpu 是一个吞吐量系统,总是超量分配线程,超量分配意味着总是在内存快的(指的是数据ready?)时候工作。(a grid represents all work to be done)所有要做的工作都被分解成线程块(the grid comprises many blocks with an equal number of threads),每个块都有并行线程,保证线程同时运行,这样它们就可以共享数据(threads within a block run independently but may synchrionze to exchange data)(机器学习有一些计算,比如all-to-all)。但所有的块都是在超量分配模式下独立调度的,这样才能两全其美。但它也允许一定数量的线程相互交互,这就是gpu编程的本质。PS:是不是可以认为,内存延迟高,这时为了cpu和内存提速(都别闲着),做大带宽,比如虽然10s传一次数据,但一次传10M,gpu 准备大量线程同时干活儿。后续有数据就干活儿,没干活儿就让位给另一批数据ready的线程。


## GPU

各种游戏里面的人物的脸,并不是那个相机或者摄像头拍出来的,而是通过多边形建模(Polygon Modeling)创建出来的。而实际这些人物在画面里面的移动、动作,乃至根据光线发生的变化,都是通过计算机根据图形学的各种计算,实时渲染出来的。
Expand Down Expand Up @@ -86,7 +90,7 @@ GPU架构总体如下图所示:

**两级线程层次结构**(带上grid也有说三层的,比较新的Hooper 架构 引入了Thread Block Clusters 层次),可以分为两个粒度来看 GPU:
1. 以SM 为基本单元来看GPU 整体架构,GPU由多个SM组成,而在SM之外,仅仅有global memory和L2 cache两个组件。PS:gpu sm 更类似于cpu 里的core,不同sm执行不同的指令单元
2. SM的硬件架构:核心组件包括内存、计算单元和指令调度。每个SM包含多个核心,它们共享一个指令单元,但能够并行执行不同的线程。每个SM中的共享内存允许线程之间进行有效的数据交换和同步
2. SM的硬件架构:核心组件包括内存、计算单元和指令调度。每个SM包含多个核心,它们共享一个指令单元,但能够并行执行不同的线程。每个SM中的共享内存允许线程之间进行有效的数据交换和同步。warp是gpu的基本调度单位。在一个是时钟周期内可以多个warp,一个sm包含64个warp,4个warps可以并行运行。

流式多处理器(Streaming Multiprocessor、SM)是 GPU 的基本单元,每个 GPU 都由一组 SM 构成,SM 中最重要的结构就是计算核心 Core
1. 线程调度器(Warp Scheduler):线程束(Warp)是最基本的单元,每个线程束中包含 32 个并行的线程,GPU 控制部件面积比较小,为了节约控制器,**一个 Warp 内部的所有 CUDA Core 的 PC(程序计数器)一直是同步的,但是访存地址是可以不同的,每个核心还可以有自己独立的寄存器组,它们使用不同的数据执行相同的命令**,这种执行方式叫做 SIMT(Single Instruction Multi Trhead)。调度器会负责这些线程的调度;
Expand Down Expand Up @@ -420,7 +424,7 @@ GPU存储可分为物理内存(硬件真实存在的)和逻辑内存(由cu

Naive GEMM的代码见下(完整代码见 sgemm_naive.cu ):

```
```c
// 将二维数组的行列索引转成一维数组的行列索引,这样可以更高效访问数据
// row, col:二维数组实际的行列索引,ld表示该数组实际的列数
// 例:二维数组实际的行列索引为(1, 3),即第二行第四个元素,二维数据的总列数 = 5
Expand Down
2 changes: 2 additions & 0 deletions _posts/MachineLearning/Infra/2024-09-28-inference_tmp.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Mooncake 采用了以 KVCache 为中心的分离式推理架构,主要由三
2. Decoding 池:这个部分集中处理所有解码阶段的任务。
3. KVCache 池:这个部分负责存储所有中间过程中应用到的 KVCache,并决定何时使用这些缓存,何时释放它们。

prefill-decode 分离架构核心是解决Continous Batching在decode中会被插入prefill从而导致decode卡顿以及decode阶段MFU低下这两个问题。

Context Caching

![](/public/upload/machine/context_caching.jpg)
Expand Down
2 changes: 2 additions & 0 deletions _posts/MachineLearning/LLM/2023-09-07-multimodal_llm.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,7 @@ curl  https://api.openai-hk.com/v1/images/generations \
多模态RAG的想法是允许RAG系统以某种方式将多种形式的信息注入到多模态模型中。因此,多模态RAG系统可能检索基于用户提示的文本、图像、视频和其他不同模态的数据,而不仅仅是检索文本片段。 有三种流行的方法可以实现多模态RAG。
1. 使用一个嵌入空间,检索出所有模态中与用户查询最相似的数据。
2. 将所有数据模态转换为单一模态,通常是文本。
1. 图片 ==> vlm ==> 文本 ==> 文本embedding
2. 图片 ==> vemb ==> embedding。 生成时 一般也是将 query + topk emb 图片 + 其它文本 传给vlm 生成答案。

[训练VLM(视觉语言模型)的经验](https://zhuanlan.zhihu.com/p/890327005) 未读。
Loading

0 comments on commit cea3a66

Please sign in to comment.