Skip to content

Commit

Permalink
add ml
Browse files Browse the repository at this point in the history
  • Loading branch information
liqiankun1111 committed Mar 4, 2024
1 parent 43d801c commit 7112134
Show file tree
Hide file tree
Showing 26 changed files with 263 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ PS: 理想状态:给到 pod 准确、实时的limit(更好的监控),

混部要解决的问题,分为单机层面和集群层面
1. Noisy Neighbor Problem,
1. 资源层面:CPU、Memory L1/L2/L3、network、blkio。
1. 资源层面:CPU、Memory L1/L2/L3、network、blkio。[如何合理使用 CPU 管理策略,提升容器性能?](https://mp.weixin.qq.com/s/N7UWOjqEnZ8oojWgFGBOlQ)
2. 硬件拓扑层面:NUMA、cpu cache、memory bandwidth、SMT
2. 在线服务类/Latency Sensitive
1. 容器混合部署时相互干扰
Expand Down
103 changes: 52 additions & 51 deletions _posts/Kubernetes/Tools/2020-07-20-client_go_informer.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,51 @@ func (f *DeltaFIFO) Get(obj interface{}) (item interface{}, exists bool, err err
疑问:DeltaFIFO 是用来传递delta/event的,不是为了来传递obj 的,watch 得到 event 用queue 缓冲一些可以理解,为何底层要搞那么复杂呢?从设计看,**evnet 在队列里可能对堆积**,比如一个 add event 新增key=a,之后又有一个update event 将key=a改为b,其实此时可以 直接合并为一个 add event 即key=b。堆积之后 仍然让 消费者依次处理所有event(`Pop()`),还是告诉它所有的event(`Get()`),还是自动帮它做合并?PS: 很多能力 因为封装的太好,以至于不知道
## Indexer(未完成)
## workqueue
因为etcd存储的缘故,k8s的性能 没有那么优秀,假设集群有几w个pod,list 就是一个巨耗时的操作,有几种优化方式
1. list 时加上 label 限定查询范围。k8s apiserver 支持根据 label 对object 进行检索
2. 使用client-go 本地cache,再进一步,根据经常查询的label/field 建立本地index。PS:apiserver 确实对label 建了索引,但是本地并没有自动建立。
[Kubernetes client-go 源码分析 - workqueue](https://mp.weixin.qq.com/s/9zHYc266cJlXGcZa-xnOFA) 讲的很详细。
[Kubernetes client-go 源码分析 - Indexer & ThreadSafeStore](https://mp.weixin.qq.com/s/YVl4z0Yr0cDp3dFg6Kwg5Q) 未细读
![](/public/upload/kubernetes/workqueue.png)
[client-go 之 Indexer 的理解](https://cloud.tencent.com/developer/article/1692517) 未细读
如果想自定义控制器非常简单,我们直接注册handler就行。但是绝大部分k8s原生控制器中,handler并没有直接处理。而是统一遵守一套:add/update/del -> queue -> run -> runWorker -> syncHandler 处理的模式。有几个好处
1. chan的功能过于单一,无法满足各类场景的需求,workqueue除了一个缓冲机制外,还有错误重试、限速等机制。
2. 利用了Indexer本地缓存机制,queue里面只包括 key就行,数据indexer里有
![](/public/upload/kubernetes/workqueue.jpg)
[Kubernetes之controller-runtime事件再处理](https://mp.weixin.qq.com/s/NTRog9zrSv3en9MV5_nJuQ) 值得细读一下。
workqueue 中内置了三种队列模型
1. Interface,实现了基本的先进先出队列, **跟常规队列相比多了去重功能**。为什么队列需要去重功能?当一个资源对象被频繁变更, 然而同一个对象还未被消费, 没必要在在队列中存多份, 经过去重后只需要处理一次即可。
2. DelayingInterface,在 Interface 的基础上, 实现了延迟队里功能。为什么需要 delay 延迟入队功能 ?有些 k8s controller 是需要延迟队列功能的, 比如像 cronjob 依赖延迟队列实现定时功能. 另外也可以实现延迟 backoff 时长后重入队.
3. RateLimitingInterface,在 DelayingInterface 的基础上, 实现了 RateLimiter 限频器功能. 当插入元素的次数超过限频器规则时, 则把对象推到延迟队列中处理.
```go
type Interface interface {
Add(item interface{}) // 添加元素
Len() int // 获取队列的长度, queue 字段的长度
Get() (item interface{}, shutdown bool) // 从队列中获取元素
Done(item interface{}) // 标记元素执行完毕
ShutDown() // 关闭
ShuttingDown() bool // 是否关闭
}
type Type struct {
// 使用 slice 切片存放元素, 顺序为 fifo 模式, 写为 append 追加, 读则从头部获取.
queue []t
// 使用一个 set 集合做去重操作, 避免未消费的队列中相同的元素.
dirty set
// 也是个 set 集合, 其目的是避免相同的元素被并发执行, 有了 processing 后, 当某个元素正在执行, 另一个生产者只能把元素放到 dirty 集合里做去重, 等待上一个元素干完了后, 这个元素才会重写入 dirty 里. 为什么不放到 queue slice 里, 因为放 queue slice 里, 并发消费场景下, 同一个元素会被多个协程并发处理.
processing set
// 条件变量, 用来唤醒等待元素的协程
cond *sync.Cond
// 用来统计指标
metrics queueMetrics
}
```
delayingQueue 的代码逻辑还是很清晰的. 首先使用数据结构小顶堆 minheap 来排列定时任务(使用readyAt作为大小依据). 当添加定时任务时, 把该任务扔到一个 chan 里, 然后由一个独立的协程监听该 chan, 把任务扔到 heap 中, 该独立协程会从堆里找到最近到期的任务, 并对该任务的进行到期监听, 当定时后期后, 会把到期的定时任务添加到 queue 队列中.
待确认:一个workqueue内只有一个类型的crd。
## controller.Run/ Watch event 消费
Expand Down Expand Up @@ -233,6 +269,16 @@ func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {
}
```
## Indexer(未完成)
因为etcd存储的缘故,k8s的性能 没有那么优秀,假设集群有几w个pod,list 就是一个巨耗时的操作,有几种优化方式
1. list 时加上 label 限定查询范围。k8s apiserver 支持根据 label 对object 进行检索
2. 使用client-go 本地cache,再进一步,根据经常查询的label/field 建立本地index。PS:apiserver 确实对label 建了索引,但是本地并没有自动建立。
[Kubernetes client-go 源码分析 - Indexer & ThreadSafeStore](https://mp.weixin.qq.com/s/YVl4z0Yr0cDp3dFg6Kwg5Q) 未细读
[client-go 之 Indexer 的理解](https://cloud.tencent.com/developer/article/1692517) 未细读
## processor 是如何处理数据的
两条主线
Expand Down Expand Up @@ -330,51 +376,6 @@ func (p *processorListener) run() {
一个eventhandler 会被封装为一个processListener,一个processListener 对应两个协程,run 协程负责 消费pendingNotifications 所有event 。pendingNotifications是一个ring buffer, 默认长度为1024,如果被塞满,则扩容至2倍大小。如果event 处理较慢,则会导致pendingNotifications 积压,event 处理的延迟增大。PS:业务实践上确实发现了 pod 因各种原因大量变更, 叠加 event 处理慢 导致pod ready 后无法及时后续处理的情况
## workqueue
[Kubernetes client-go 源码分析 - workqueue](https://mp.weixin.qq.com/s/9zHYc266cJlXGcZa-xnOFA) 讲的很详细。
![](/public/upload/kubernetes/workqueue.png)
如果想自定义控制器非常简单,我们直接注册handler就行。但是绝大部分k8s原生控制器中,handler并没有直接处理。而是统一遵守一套:add/update/del -> queue -> run -> runWorker -> syncHandler 处理的模式。有几个好处
1. chan的功能过于单一,无法满足各类场景的需求,workqueue除了一个缓冲机制外,还有错误重试、限速等机制。
2. 利用了Indexer本地缓存机制,queue里面只包括 key就行,数据indexer里有
![](/public/upload/kubernetes/workqueue.jpg)
[Kubernetes之controller-runtime事件再处理](https://mp.weixin.qq.com/s/NTRog9zrSv3en9MV5_nJuQ) 值得细读一下。
workqueue 中内置了三种队列模型
1. Interface,实现了基本的先进先出队列, 跟常规队列相比多了去重功能。为什么队列需要去重功能?当一个资源对象被频繁变更, 然而同一个对象还未被消费, 没必要在在队列中存多份, 经过去重后只需要处理一次即可。
2. DelayingInterface,在 Interface 的基础上, 实现了延迟队里功能。为什么需要 delay 延迟入队功能 ?有些 k8s controller 是需要延迟队列功能的, 比如像 cronjob 依赖延迟队列实现定时功能. 另外也可以实现延迟 backoff 时长后重入队.
3. RateLimitingInterface,在 DelayingInterface 的基础上, 实现了 RateLimiter 限频器功能. 当插入元素的次数超过限频器规则时, 则把对象推到延迟队列中处理.
```go
type Interface interface {
Add(item interface{}) // 添加元素
Len() int // 获取队列的长度, queue 字段的长度
Get() (item interface{}, shutdown bool) // 从队列中获取元素
Done(item interface{}) // 标记元素执行完毕
ShutDown() // 关闭
ShuttingDown() bool // 是否关闭
}
type Type struct {
// 使用 slice 切片存放元素, 顺序为 fifo 模式, 写为 append 追加, 读则从头部获取.
queue []t
// 使用一个 set 集合做去重操作, 避免未消费的队列中相同的元素.
dirty set
// 也是个 set 集合, 其目的是避免相同的元素被并发执行, 有了 processing 后, 当某个元素正在执行, 另一个生产者只能把元素放到 dirty 集合里做去重, 等待上一个元素干完了后, 这个元素才会重写入 dirty 里. 为什么不放到 queue slice 里, 因为放 queue slice 里, 并发消费场景下, 同一个元素会被多个协程并发处理.
processing set
// 条件变量, 用来唤醒等待元素的协程
cond *sync.Cond
// 用来统计指标
metrics queueMetrics
}
```
delayingQueue 的代码逻辑还是很清晰的. 首先使用数据结构小顶堆 minheap 来排列定时任务(使用readyAt作为大小依据). 当添加定时任务时, 把该任务扔到一个 chan 里, 然后由一个独立的协程监听该 chan, 把任务扔到 heap 中, 该独立协程会从堆里找到最近到期的任务, 并对该任务的进行到期监听, 当定时后期后, 会把到期的定时任务添加到 queue 队列中.
待确认:一个workqueue内只有一个类型的crd。
## 细节
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ML 是一个通过算法和统计模型从数据中学习知识的学科,当

人工神经网络具有自学习和自适应能力,可以通过预先提供的一批相对应的输入输出数据,分析两者的内在关系和规律, 最终通过这些规律形成一个**复杂的非线性系统函数**,这种学习分析过程被称作训练。PS:模型可以看作一个函数,它模拟了人类智能的运行方式。在模型训练中,你所做的就是解出这个函数中未知变量的值。

机器学习(Machine Learning),它指的是这样一种计算过程:对于给定的训练数据(Training samples),选择一种先验的数据分布模型(Models),然后借助优化算法(Learning Algorithms)自动地持续调整模型参数(Model Weights / Parameters),从而让模型不断逼近训练数据的原始分布。这个持续调整模型参数的过程称为“模型训练”(Model Training)。模型的训练依赖于优化算法,基于过往的计算误差(Loss),优化算法以不断迭代的方式,自动地对模型参数进行调整。由于模型训练是一个持续不断的过程,那么自然就需要一个收敛条件(Convergence Conditions),来终结模型的训练过程。一旦收敛条件触发,即宣告模型训练完毕。模型训练完成之后,我们往往会用一份新的数据集(Testing samples),去测试模型的预测能力,从而验证模型的训练效果,这个过程,我们把它叫作“模型测试”(Model Testing)。测试数据用于考察模型的泛化能力(Generalization),也就是说,对于一份模型从来没有“看见过”的数据,我们需要知道,模型的预测能力与它在训练数据上的表现是否一致。
机器学习(Machine Learning),它指的是这样一种计算过程:对于给定的训练数据(Training samples),选择一种先验的数据分布模型(Models),然后借助优化算法(Learning Algorithms)自动地持续调整模型参数(Model Weights / Parameters),从而让模型不断逼近训练数据的原始分布。这个持续调整模型参数的过程称为“模型训练”(Model Training)。模型的训练依赖于优化算法,基于过往的计算误差(Loss),优化算法以不断迭代的方式,自动地对模型参数进行调整。由于模型训练是一个持续不断的过程,那么自然就需要一个收敛条件(Convergence Conditions),来终结模型的训练过程。一旦收敛条件触发,即宣告模型训练完毕。模型训练完成之后,我们往往会用一份新的数据集(Testing samples),去测试模型的预测能力,从而验证模型的训练效果,这个过程,我们把它叫作“模型测试”(Model Testing)。测试数据用于考察模型的泛化能力(Generalization),也就是说,对于一份模型从来没有“看见过”的数据,我们需要知道,模型的预测能力与它在训练数据上的表现是否一致。PS:机器学习就是找函数

## AI 的范畴

Expand Down
2 changes: 2 additions & 0 deletions _posts/MachineLearning/2022-01-27-recommend_system_note.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ print('\n\nTest Loss {}, Test Accuracy {}'.format(test_loss, test_accuracy)

[谈一谈LLM在推荐域的一些理解](https://mp.weixin.qq.com/s/9f87dKcFNfGm6Q-jJNdJEw)

[百度基于云原生的推荐系统设计与实践](https://mp.weixin.qq.com/s/h-oNQNW8_97UX9PKixR--Q)

## 其它

[推荐系统中比模型结构更重要的是什么?](https://mp.weixin.qq.com/s/I1ylBlPfqrToezs2Ml-Dtw) 未读。
Expand Down
2 changes: 1 addition & 1 deletion _posts/MachineLearning/2022-02-10-large_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ AI for Science的出现,让高性能计算与AI融合成为刚需, tensor pa
2. 流水线并行:多机一组,通信量在 MB 量级,机间同号卡进行 P2P 通信。
3. 张量并行:考虑到通信量数百 GB,在单机内并行,借助单机内 NVLink 这样的高速互联通信能力。

**不同的并行性技术会引入不同程度的通信开销和计算延迟**。在深度学习训练过程中,GPU需要大量的数据进行计算,但是如果数据没有及时传输到GPU就会导致GPU处于等待状态,浪费GPU的计算能力。因此,CPU卸载技术就应运而生,通过让CPU负责将数据传输到GPU,可以让GPU专心计算,提高训练速度。CPU卸载还可以帮助减少GPU内存的使用,降低训练过程中的内存压力。卸载分为多种类型,包括数据卸载、模型卸载、梯度卸载等。数据卸载是指将数据卸载到存储设备(例如硬盘)中,用的时候传输到GPU中,其他的类似。
**不同的并行性技术会引入不同程度的通信开销和计算延迟**由于现实的互联所能实现的带宽延迟,并行度永远不可能无限扩展,一定会限制在一定尺度内,甚至非常有限的尺度内。在深度学习训练过程中,GPU需要大量的数据进行计算,但是如果数据没有及时传输到GPU就会导致GPU处于等待状态,浪费GPU的计算能力。因此,CPU卸载技术就应运而生,通过让CPU负责将数据传输到GPU,可以让GPU专心计算,提高训练速度。CPU卸载还可以帮助减少GPU内存的使用,降低训练过程中的内存压力。卸载分为多种类型,包括数据卸载、模型卸载、梯度卸载等。数据卸载是指将数据卸载到存储设备(例如硬盘)中,用的时候传输到GPU中,其他的类似。

[Galvatron项目原作解读:大模型分布式训练神器,一键实现高效自动并行](https://mp.weixin.qq.com/s/nqmfZSKdYD8JPtZwvQtWZw)稠密大模型拥有着动辄数十亿、百亿甚至万亿规模的参数量,面临高昂的计算、存储、以及通信成本,为 AI 基础设施带来了巨大的挑战。人们研发了很多工具(如 Megatron、DeepSpeed、FairSeq 等)来实现如数据并行、张量模型并行、流水并行、分片数据并行等各种并行范式。但这种粗粒度的封装逐渐难以满足用户对系统效率和可用性的需要。如何通过系统化、自动化的方式实现大模型分布式训练,已经成为了当前 MLSys 领域最为重要的问题之一。最近已经有一些系统开始提及“自动并行”的概念,但它们大部分都还停留在对 API 和算子进行工程上的封装,仍然依赖用户人工反复尝试或系统专家经验才能完成部署,并没有从根本上解决自动并行难题。近日,北大河图团队提出了一套面向大模型的自动并行分布式训练系统 Galvatron,相比于现有工作在多样性、复杂性、实用性方面均具有显著优势,性能显著优于现有解决方案。

Expand Down
4 changes: 2 additions & 2 deletions _posts/MachineLearning/2023-09-04-llm_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ keywords: llm source
开箱即用的 pipelines,它封装了预训练模型和对应的前处理和后处理环节。
1. 预处理 (preprocessing),**Transformer模型无法直接处理原始文本字符串**;具体地,我们会使用每个模型对应的分词器 (tokenizer) 来进行。 PS: 有点类似于tf的各种FeatureColumn
1. 将输入切分为词语、子词或者符号(例如标点符号),统称为 tokens;
2. 根据模型的词表将每个 token 映射到对应的 token 编号/id;
3. 根据模型的需要,添加一些额外的输入。比如tokens补齐和截断操作
2. 根据模型的词表将每个 token 映射到对应的 token 编号/id;映射通常是通过创建文本语料库中标记的词汇表,并根据每个标记在语料库中的出现频率为其分配一个整数值来执行的。最常见的tokens被分配较低的整数值,而不太常见的标记被分配较高的值。
3. 根据模型的需要,添加一些额外的输入。比如tokens补齐和截断操作,填充是指在短序列的末尾添加额外的令牌(通常是一个特殊的令牌,如[PAD])以使它们具有相同的长度的过程。这样做是为了使模型可以同时处理批处理中的所有序列。另一方面,截断是指切断较长序列的末端,如果输入序列比最大长度长,标记器将从右侧截断输入序列。
2. 将处理好的输入送入模型;
3. 对模型的输出进行后处理 (postprocessing),将其转换为人类方便阅读的格式。

Expand Down
10 changes: 9 additions & 1 deletion _posts/MachineLearning/2023-09-07-multimodal.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@ keywords: llm multimodal

[​浅析多模态大模型的前世今生](https://mp.weixin.qq.com/s/DXoeQqjVoDLxGV2oZeL95Q) 未读

[文生图模型发展简史与原理:DALL·E, Imagen, Stable Diffusion](https://mp.weixin.qq.com/s/3-p16x4e5XVRYuPj6QTnxg) 未读
[文生图模型发展简史与原理:DALL·E, Imagen, Stable Diffusion](https://mp.weixin.qq.com/s/3-p16x4e5XVRYuPj6QTnxg) 未读

## 文生视频

[领先99%小白的Sora关键信息](https://mp.weixin.qq.com/s/MsaCUnTsJYxJFgnNGT6DTA)

[一文带你了解OpenAI Sora](https://mp.weixin.qq.com/s/Efk-gP8iuau3crWB2wWizg)

[OpenAI 的 ​Sora 技术报告详解](https://mp.weixin.qq.com/s/MyWPPY19wwsJv8zdBMxdFg)
Loading

0 comments on commit 7112134

Please sign in to comment.