Skip to content

Commit

Permalink
add ml
Browse files Browse the repository at this point in the history
  • Loading branch information
liqiankun1111 committed Sep 28, 2024
1 parent cc644de commit ad3f88e
Show file tree
Hide file tree
Showing 29 changed files with 329 additions and 117 deletions.
6 changes: 5 additions & 1 deletion _posts/Kubernetes/Network/2015-03-04-kubernetes_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ spec:
Ingress和Pod、Servce等等类似,被定义为kubernetes的一种资源。本质上说Ingress只是存储在etcd上面一些数据,我们可以通过kubernetes的apiserver添加删除和修改ingress资源。
有了 Ingress 这样一个统一的抽象,Kubernetes 的用户就无需关心 Ingress 的具体细节了。在实际的使用中,你只需要从社区里选择一个具体的 Ingress Controller,把它部署在 Kubernetes 集群里即可。这个 Ingress Controller 会根据你定义的 Ingress 对象,提供对应的代理能力。目前,业界常用的各种反向代理项目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已经为 Kubernetes 专门维护了对应的 Ingress Controller。
有了 Ingress 这样一个统一的抽象,Kubernetes 的用户就无需关心 Ingress 的具体细节了。在实际的使用中,你只需要从社区里选择一个具体的 Ingress Controller,把它部署在 Kubernetes 集群里即可。这个 Ingress Controller 会根据你定义的 Ingress 对象,提供对应的代理能力。目前,业界常用的各种反向代理项目,比如 Nginx、HAProxy、Envoy、Traefik 等,都已经为 Kubernetes 专门维护了对应的 Ingress Controller。PS: **把nginx 搬到k8s上,把路由规则 k8s object化**,service作为backend。
### Ingress Controller 部署和实现
Expand Down Expand Up @@ -316,6 +316,10 @@ server {
}
```
### 进化
[超越 Gateway API:深入探索 Envoy Gateway 的扩展功能](https://mp.weixin.qq.com/s/n258ul1Tqe27NJ0WAHK4MA)Ingress 是 Kubernetes 中定义集群入口流量规则的 API 资源。Ingress API 为用户提供了基本的定义 HTTP 路由规则的能力,但是 Ingress API 的功能非常有限,只提供了按照 Host、Path 进行路由和 TLS 卸载的基本功能。在实际应用中, Ingress API 的基本功能往往无法满足应用程序复杂的流量管理需求。这导致各个 Ingress Controller 实现需要通过 Annotations 或者自定义 API 资源等非标准的方式来扩展 Ingress API 的功能。这些非标准的扩展方式都导致 Ingress API 的可移植性变差,用户在不同的 Ingress Controller 之间切换时,需要重新学习和配置不同的 API 资源。分裂的 Ingress API 也不利于社区的统一和发展。为了解决 Ingress API 的问题,Kubernetes 社区提出了 Gateway API,Gateway API 是一个新的 API 规范,旨在提供一个统一的、可扩展的、功能丰富的 API 来定义集群入口流量规则。Gateway API 定义了多种资源,包括 Gateway、HTTPRoute、GRPCRoute、TLSRoute、TCPRoute、UDPRoute 等。原来很多需要通过 Annotations 或者自定义 API 资源来扩展的功能,现在都可以直接通过 Gateway API 来实现。但是任何一个标准,不管定义得多么完善,理论上都只能是其所有实现的最小公约数。Gateway API 作为一个通用的 API 规范,为了保持通用性,无法对一些和具体实现细节相关的功能提供直接的支持。例如,虽然请求限流、权限控制等功能在实际应用中非常重要,但是不同的数据平面如 Envoy,Nginx 等的实现方式各有不同,因此 Gateway API 无法提供一个通用的规范来支持这些功能。Gateway API 提供了 Policy Attachment 扩展机制,允许各个 Controller 实现在不修改 Gateway API 的情况下,通过关联自定义的 Policy 到 Gateway 和 HTTPRoute 等资源上,以实现对流量的自定义处理。此外,Gateway API 还支持将自定义的 Backend 资源关联到 HTTPRoute 和 GRPCRoute 等资源上,以支持将流量路由到自定义的后端服务。支持在 HTTPRoute 和 GRPCRoute 的规则中关联自定义的 Filter 资源,以支持对请求和响应进行自定义处理。
## Services without selectors
**Services, in addition to providing abstractions to access Pods, can also abstract any kind of backend(service不仅可以做访问pod的桥梁,还可以做访问任何后端的桥梁)**. For example:
Expand Down
4 changes: 2 additions & 2 deletions _posts/Kubernetes/Tools/2022-04-08-kustomize_helm.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---

layout: post
title: helm
title: K8S YAML 资源清单管理方案
category: 架构
tags: Kubernetes
keywords: Kubernetes 混部
Expand Down Expand Up @@ -65,7 +65,7 @@ k8s
└── kustomization.yaml
```

一个由 kustomize 管理的应用结构,它主要由 base 和 overlays 组成。Kustomize 使用 Base、Overlay 和 Patch 生成最终配置文件的思路,与 Docker 中分层镜像的思路有些相似(PS:所以叫overlays,指定 Kubernetes 将使用哪些策略修补资源),这样的方式既规避了以“字符替换”对资源元数据文件的入侵,也不需要用户学习额外的 DSL 语法(比如 Lua)。但是,毕竟 Kustomize 只是一个“小工具”性质的辅助功能,**要做的事、要写的配置,最终都没有减少,只是不用反复去写罢了**。PS:`kubectl apply -k 带有 kustomization.yaml的目录` 就可以看做 `kubectl apply -f kustomization.yaml 引用的所有resource manifest`
一个由 kustomize 管理的应用结构,它主要由 base 和 overlays 目录组成,Base下存放的是模版文件(一般是在base下维护全量yaml?),Overlays是不同环境的差异化管理目录,这两个目录下都需要有kustomization.yaml文件,这个文件用于描述如何生成定制的资源。Kustomize 使用 Base、Overlay 和 Patch 生成最终配置文件的思路,与 Docker 中分层镜像的思路有些相似(PS:所以叫overlays,指定 Kubernetes 将使用哪些策略修补资源),这样的方式既规避了以“字符替换”对资源元数据文件的入侵,也不需要用户学习额外的 DSL 语法(比如 Lua)。但是,毕竟 Kustomize 只是一个“小工具”性质的辅助功能,**要做的事、要写的配置,最终都没有减少,只是不用反复去写罢了**。PS:`kubectl apply -k 带有 kustomization.yaml的目录` 就可以看做 `kubectl apply -f kustomization.yaml 引用的所有resource manifest`

Kustomize 提供的两个核心功能 —— 聚合资源和修补字段。

Expand Down
4 changes: 2 additions & 2 deletions _posts/MachineLearning/Framework/2023-12-16-llm_train.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ PS:ZeRO是一种显存优化的数据并行(data parallelism, DP)方案,它

最后总结一下, 针对大模型的训练有三种并行策略,理解起来并不复杂:
1. 数据并行:模型的计算过程没有分割,训练数据是分割并行处理的。
1. 模型并行:模型的计算过程被分割。
1. 模型并行:模型的计算过程被分割。把一个模型拆为两半,那么这两半的模型都得用同一批数据去跑才行,模型并行是模型太大不得已的对模型进行肢解的一种并行
2. 流水线并行:模型按照层(Layer)切分。
2. 张量并行:把参数张量切分,并且将矩阵乘法分解后多 GPU 并行计算。
2. 张量并行:把参数张量切分,并且将矩阵乘法分解后多 GPU 并行计算**只有在线性层中会出现张量并行**
3. 训练一方面是要我们把本身算子的性能做好,把一张卡本身的计算效率做高。第二个我们做计算跟通讯的overlap,尽量让计算不要停止,不要等待通讯。
3. 训练本身是一个并行计算,每计算一个step后会同步权重,这时就牵扯到框架层面的事情了。我们常说5D并行的策略,本质上是让计算跟通讯变得更高效。这里面核心的一个原理,其实就是让计算和通讯是overlap的,也就是说**在通讯传递这些权重的时候**,计算不会等待,也就是TP、PP、DP、EP这些并行的策略在通讯的时候,GPU已经进入下一次计算了,把计算跟通讯拆开。

Expand Down
37 changes: 36 additions & 1 deletion _posts/MachineLearning/Infra/2021-08-18-gpu_utilization.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,45 @@ GPU计算单元类似于CPU中的核,用来进行数值计算。衡量计算
[教你如何继续压榨GPU的算力——MPS](https://zhuanlan.zhihu.com/p/346389176)

### 显存
对于如下图所示的一个全连接网络(不考虑偏置项b)
![](/public/upload/machine/mlp_memory.jpg)

模型的显存占用包括:
1. 参数:二维数组 W
2. 模型的输出:二维数组 Y
输入X可以看成是上一层的输出,因此把它的显存占用归于上一层。

**参数的显存占用**。只有有参数的层,才会有显存占用。这部份的显存占用和输入无关,模型加载完成之后就会占用。
1. 有参数的层主要包括:
1. 卷积 ,Conv2d(Cin, Cout, K): 参数数目:Cin × Cout × K × K。
2. 全连接,Linear(M->N) 参数数目:M×N。计算量:BxMxN
3. BatchNorm,BatchNorm(N) 参数数目:2N。计算量:BHWC*{4,5,6}
4. Embedding层,Embedding(N,W) 参数数目:N × W
5. ...
2. 无参数的层:
1. 多数的激活层(Sigmoid/ReLU)。 计算量:BHWC
2. 池化层。计算量:BHWCK^2
3. Dropout
4. ...

参数占用显存 = 参数数目×n(n = 4 :float32;)。在PyTorch中,当你执行完model=MyGreatModel().cuda()之后就会占用相应的显存,占用的显存大小基本与上述分析的显存差不多。

**梯度与动量的显存占用**:优化器如果是SGD,需要保存动量, 因此显存x3,如果是Adam优化器,动量占用的显存更多,显存x4。

总结一下,模型中与输入无关的显存占用包括:
1. 参数 W
2. 梯度 dW(一般与参数一样)
3. 优化器的动量(普通SGD没有动量,momentum-SGD动量与梯度一样,Adam优化器动量的数量是梯度的两倍)

**输入输出的显存占用** :需要计算每一层的feature map的形状(多维数组的形状);模型输出的显存占用与 batch size 成正比;需要保存输出对应的梯度用以反向传播(链式法则);模型输出不需要存储相应的动量信息(因为不需要执行优化)。

[科普帖:深度学习中GPU和显存分析](https://mp.weixin.qq.com/s/K_Yl-MD0SN4ltlG3Gx_Tiw)

显存占用 = 模型显存占用(参数 + 梯度与动量 + 模型输出) + batch_size × 每个样本的显存占用

AlexNet的分析如下图,左边是每一层的参数数目(不是显存占用),右边是消耗的计算资源
![](/public/upload/machine/AlexNet_gpu.jpg)

### 单机

`nvidia-smi` 查看某个节点的gpu 情况
Expand Down Expand Up @@ -179,7 +214,7 @@ GPU计算单元类似于CPU中的核,用来进行数值计算。衡量计算

其它技巧:调用 watch -n 1 nvidia-smi 可以每一秒进行自动的刷新。nvidia-smi 也可以通过添加 --format=csv 以 CSV 格式输。在 CSV 格式中,可以通过添加 `--gpu-query=...` 参数来选择显示的指标。为了实时显示 CSV 格式并同时写入文件,我们可以将 nvidia-smi 的输出传输到 tee 命令中,`nvidia-smi --query-gpu=timestamp,pstate,temperature.gpu,utilization.gpu,utilization.memory,memory.total,memory.free,memory.used --format=csv | tee gpu-log.csv`。这将写入我们选择的文件路径。

gpustat,直接pip install gpustat即可安装,gpustat基于nvidia-smi,可以提供更美观简洁的展示,结合watch命令,可以动态实时监控GPU的使用情况。`watch --color -n1 gpustat -cpu`
这里推荐一个好用的小工具:**gpustat**,直接pip install gpustat即可安装,gpustat基于nvidia-smi,可以提供更美观简洁的展示,结合watch命令,可以动态实时监控GPU的使用情况。`watch --color -n1 gpustat -cpu`


### exporter
Expand Down
5 changes: 4 additions & 1 deletion _posts/MachineLearning/Infra/2024-07-07-vllm.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ running队列中的seq_group不一定能继续在本次调度中被选中做推

在1次推理中,所有seq_group要么一起做prefill(来自running队列),要么一起做decode(来自running + swapped队列)。先做哪个呢?
1. 以swapped是否非空为判断入口。如果当前调度步骤中swapped队列非空,说明在之前的调度步骤中这些可怜的seq_group因为资源不足被抢占,而停滞了推理。所以根据FCFS规则,当gpu上有充足资源时,我们应该先考虑它们,而不是考虑waiting队列中新来的那些seq_group。
2. waiting队列是否达到调度间隔阈值。在做推理时,waiting队列中是源源不断有seq_group进来的,一旦vLLM选择调度waiting队列,它就会停下对running/swapped中seq_group的decode处理,转而去做waiting中seq_group的prefill,也即vLLM必须在新来的seq_group和已经在做推理的seq_group间取得一种均衡:既不能完全不管新来的请求,也不能耽误正在做推理的请求。所以“waiting队列调度间隔阈值”就是来控制这种均衡的。
2. waiting队列是否达到调度间隔阈值。在做推理时,waiting队列中是源源不断有seq_group进来的,一旦vLLM选择调度waiting队列,它就会停下对running/swapped中seq_group的decode处理,转而去做waiting中seq_group的prefill,也即vLLM必须在新来的seq_group和已经在做推理的seq_group间取得一种均衡:既不能完全不管新来的请求,也不能耽误正在做推理的请求。所以“waiting队列调度间隔阈值”就是来控制这种均衡的。PS:将Prefill和Decode阶段放在同一个 GPU 上处理,优先prefill 会导致TPOT(每个输出 Token 的时间)增加。反之,如果优先解码,TTFT(首次 Token 时间)也会增加。
1. 调度间隔设置得太小,每次调度都只关心waiting中的新请求,这样发送旧请求的用户就迟迟得不到反馈结果。且此时waiting队列中积累的新请求数量可能比较少,不利于做batching,浪费了并发处理的能力。
2. 调度间隔设置得太大,waiting中的请求持续挤压,同样对vLLM推理的整体吞吐有影响。
3. 内存空间是否充足?
Expand Down Expand Up @@ -741,6 +741,9 @@ vLLM可以算是非常成功,对大模型发展的贡献也是史诗级的。

大模型推理引擎经过一年多发展,进入了一个关键的调整期。一方面,**针对定制集群的分离式架构出现**,很多业务方自己定制更复杂的并行和调度方案。另一方面,LLM的用法更加复杂,催生了LLM Programs使用范式。此外,非NVIDIA的NPU如雨后春笋般涌现,它们独特的硬件特性亟待新的系统架构来充分挖掘与利用。在这一背景下,以vLLM为代表的开源LLM推理引擎正面临着前所未有的进化压力。而SGLang此次的升级,不仅从框架层面揭示了vLLM仍有巨大的提升潜力,也对LLM场景需求进行了一些探索,值得大家关注。PS:其实就是应用层的信息(比如system prompt共用、输出json)进一步透传到底层,以优化底层的调度及显存使用。甚至部分应用层控制流通过dsl下传到调度层做。

## 算子层

[vLLM皇冠上的明珠:深入浅出理解PagedAttention CUDA实现](https://zhuanlan.zhihu.com/p/673284781) 未细读。


## 其他
Expand Down
28 changes: 28 additions & 0 deletions _posts/MachineLearning/Infra/2024-09-28-inference_tmp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---

layout: post
title: 大模型推理tips
category: 架构
tags: MachineLearning
keywords: llm vLLM

---

* TOC
{:toc}

<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

## 简介(未完成)

## 以kvcache为核心的分布式架构

Mooncake 采用了以 KVCache 为中心的分离式推理架构,主要由三个核心部分组成:

1. Prefill 池:这个部分负责集中管理所有的预填充阶段的计算任务。
2. Decoding 池:这个部分集中处理所有解码阶段的任务。
3. KVCache 池:这个部分负责存储所有中间过程中应用到的 KVCache,并决定何时使用这些缓存,何时释放它们。

Context Caching

![](/public/upload/machine/context_caching.jpg)
2 changes: 1 addition & 1 deletion _posts/MachineLearning/LLM/2023-09-04-llm_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ class Qwen2Attention(nn.Module):
key_states = repeat_kv(key_states, self.num_key_value_groups)
value_states = repeat_kv(value_states, self.num_key_value_groups)
# 使用dot attn实现q*kT/hd_d^0.5
attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim)
attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim) # # 多维矩阵乘法
# 然后 attn_weights 加上 attention_mask,实现读取顺序
attn_weights = attn_weights + attention_mask
# softmax + dropout + values_states相乘
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class LoRALayer(nn.Module):
self.B = nn.Parameter(torch.randn(rank, original_layer.weight.size(1)))

def forward(self, x):
delta_w = torch.matmul(self.A, self.B)
delta_w = torch.matmul(self.A, self.B) # 多维矩阵乘法
return self.original_layer(x) + torch.matmul(x, delta_w.t())

# 示例:在Transformer模型中使用LoRA层
Expand Down
Loading

0 comments on commit ad3f88e

Please sign in to comment.