diff --git a/_posts/MachineLearning/LLM/2024-08-17-llm_pre_training.md b/_posts/MachineLearning/LLM/2024-08-17-llm_pre_training.md index 6d1fafb4..6392aecf 100644 --- a/_posts/MachineLearning/LLM/2024-08-17-llm_pre_training.md +++ b/_posts/MachineLearning/LLM/2024-08-17-llm_pre_training.md @@ -8,6 +8,8 @@ keywords: llm pretrain --- + + * TOC {:toc} @@ -35,12 +37,37 @@ keywords: llm pretrain 3. 老板准备 1 个月后开发布会,给的资源是 100 张 A100,应该用多少数据训多大的模型效果最好? 4. 老板对现在 10B 的模型不满意,想知道扩大到 100B 模型的效果能提升到多少? 大模型的 Scaling Law 是 OpenAI 在 2020 年提出的概念,具体如下: -1. 对于 Decoder-only 的模型,计算量 C(Flops), 模型参数量 N,数据大小 D(token 数),三者满足:C≈6ND。 +1. 对于 Decoder-only 的模型,计算量 C(Flops), 模型参数量 N,数据大小 D(token 数),三者满足:$C \approx 6ND$ 2. 模型的最终性能主要与计算量 C,模型参数量 N 和数据大小 D 三者相关,而与模型的具体结构(层数/深度/宽度)基本无关。固定模型的总参数量,调整层数/深度/宽度,不同模型的性能差距很小,大部分在 2% 以内。 3. 对于计算量 𝐶,模型参数量 𝑁 和数据大小 𝐷,当不受其他两个因素制约时,模型性能与每个因素都呈现幂律关系。根据幂律定律,模型的参数固定,无限堆数据并不能无限提升模型的性能,模型最终性能会慢慢趋向一个固定的值。 4. 为了提升模型性能,模型参数量 N 和数据大小 D 需要同步放大,但模型和数据分别放大的比例还存在争议。 5. Scaling Law 不仅适用于语言模型,还适用于其他模态以及跨模态的任务: +对于 Decoder-only 的模型,计算量C(Flops),模型参数量 N(除去 Embedding 部分),数据大小 D(token 数),三者的关系为: C≈6ND。推导如下,记模型的结构为:decoder 层数l,attention隐层维度d,attention feedforward层维度 $d_{ff}$,一般来说 $d_{ff} = 4 * d$。 +模型的参数量N(忽略emebedding、norm和bias) 计算如下,transformer 每层包含 self-attention 和mlp 两个部分 +1. self-attention 的参数为$W_q$、$W_k$、$W_v$、$W_o$,每个矩阵的维度为$R^{d*d}$,整体参数量:$4 * d^2$ +2. mlp 的参数为 $W_1$(维度为$R^{d*d_{ff}}$)和$W_2$(维度为$R^{d_{ff}*d}$),整体参数量:$2 * d * d_ff = 2 * d * 4d = 8d^2$ +3. 所以每层参数是$4d^2 + 8d^2 = 12d^2$,全部l 层的参数量为 $12*ld^2$,即$N=12*ld^2$ + +计算量的单位是FLOPS,float point operations 对于矩阵A (m*n)和B(n*p) AB 相乘的计算量为2mnp,一次加法一次乘法。假设decoder 层的输入X(b*s*d),b为batch size,s为序列长度,d为模型维度。 + +1. 前向推理的计算量: + 1. self-attention 部分的计算: + 1. 输入线性层,$XW_q$、$XW_k$、$XW_v$,计算量为 $3 * b * s * d * d * 2 = 6bsd^2$ + 2. attention 计算 $QK^T$,计算量为 $2 * b * s* s * d = 2bs^2d$ + 3. score 与V 的计算,$S_{attention}V$,计算量为 $b*2 * s * s * d = 2bs^2d$ + 4. 输出线性层 $X^{\prime} W_O$,计算量为 $b * 2 * s * d * d = 2bsd^2$ + 2. MLP 部分的计算: + 1. 升维 $XW_1$,计算量为 $b * 2 * s * d * 4d = 8bsd^2$ + 2. 降维 $XW_2$,计算量为 $b * 2 * s * 4d * d = 8bsd^2$ + 3. 所以整个decoder层的计算量为 $24bsd^2 + 4bs^2d$,全部l层为 $C_{forward}=24bsd^2 + 4bs^2d$。 +2. 反向传播计算量是正向的2倍,所以全部计算量为 $C=3*C_{forward} = 72bsd^2 + 12bs^2d$。 +3. 平均每个token的计算量为 $C_{token}=\frac{C}{b s} = 72ld^2 + 12lsd = 6N (1+\frac{s}{6 d}) \approx 6N(s \le 6d)$ +4. 所以对于包含全部D个token的数据集 $C = C_{token}D \approx 6ND$ + +PS:mlp参数量和计算量都不输attention。 $C_{token} \approx 6N$ 可以认为是正反向3倍*加法乘法2倍=6倍。再拿到GPU的算力 * GPU 个数,就可以根据 +$C \approx 6ND$ 计算训练的耗时了。 + ## 数据准备 [聊一聊做Pretrain的经验](https://mp.weixin.qq.com/s/pUJsZVBN_Gh2yBF3g5XhKA)pretrain 大模型的第一件事:先找个 10T 左右的训练数据吧。至于怎么获取数据,爬网页、逛淘宝、联系数据贩子,等等等等。算法同学往往搞不定这个事情,你敢爬他就敢封你 IP,你爬得起劲他甚至还可以起诉你,所以这个工作最好还是让专业的数据团队同学来做。好在,世上还是好人多!今年再做 pretrain 工作,网上的开源数据集已经很多了。FineWeb、pile、Skypile、RedPajama,凑合着差不多能当启动资金来用。但从另一个角度讲,世界上没有免费的午餐,所有开源出来的中文大模型数据集,我不认为是他们最干净的数据,质量多少都有点问题。准备数据还要懂得一个基础概念:数据的知识密度是有差异的。“唐诗三百首”的知识量要远远大于“中国新闻网的三百篇新闻”。而这种高知识密度的训练数据,往往都是需要花钱的。最近,一种新的数据趋势是“合成高知识密度数据”,把几千字的新闻概括成几百字喂给模型,四舍五入也等于训练速度提高了十倍。 diff --git a/_posts/MachineLearning/Model/2016-06-05-deep_learning_intro.md b/_posts/MachineLearning/Model/2016-06-05-deep_learning_intro.md index 6818b551..ace6e11c 100644 --- a/_posts/MachineLearning/Model/2016-06-05-deep_learning_intro.md +++ b/_posts/MachineLearning/Model/2016-06-05-deep_learning_intro.md @@ -74,6 +74,20 @@ Let's talk RNN. Recurrent networks are basically neural networks that evolve thr 3. 大模型会催生**AI原生应用**。比如,DoNotPay,是一个用AI帮人打官司、写法律文书的应用,AI帮你把不该付的钱要回来。Jasper是一个通过Al帮助企业和个人写营销推广文案的应用。Speak是韩国一个学外语的应用。大模型成为一对一的教师,为每一个孩子提供个性化教育。未来,所有的应用都将基于大模型来开发,每一个行业都应该有属于自己的大模型,大模型会深度融合到实体经济当中去。**云计算的游戏规则彻底被改变,客户选择云厂商,主要会看你的模型好不好,框架好不好,而不是算力、存储这些传统能力**。 4. 大模型改变人工智能的背后,IT技术栈也发生了非常根本的变化。过去,无论是PC还是移动时代, IT技术栈都是三层,芯片层、操作系统层、应用层。人工智能时代,IT技术栈变成了四层:底层仍然是芯片层,但主流芯片从CPU变成了GPU。芯片上面叫做框架层,就是深度学习框架。框架上面是模型层,最上面才是应用层,就是我们前面提到的这些AI原生应用。 +## 分类 + +1. 强化学习 +2. 深度学习 + 1. 监督学习 + 2. 无监督学习 + 1. 生成式学习:GAN、VAE。 + 2. 对比式学习。 + +VAE 举个例子,给一张图片P1,将其模糊化处理P2,训练模型使其根据P2 可以生成P1,这样就可以得到一个模型可以对图片进行去模糊处理(比如去水印)。 + +对比式学习举一个例子,直接问一个模型图片是啥,可能对模型有点难,至少需要大量的标注数据。给一张图片P1,我们可以对图片做一些处理得到P11(正样本),再随机给另一张图片P2(负样本),此时我们控制损失函数让模型处理P1与P2的“距离”大于P1与P11的“距离”。 + +用监督信号训模型,模型只是尝试从input里面学习一些pattern,并且建立pattern和label的关系。对比学习是强迫模型从输入中找出一些pattern,并且要建立起pattern和pattern的关系。所以,模型通过对比学习能学习到pattern更丰富的语义信息。这个事情在一定程度上和人类的学习方式是一样的。我们每天视觉看到很多图像。虽然我们没有强迫自己记忆每一幅画面,但是我们的脑子已经不自觉地学习到了事物之间的关系。比如你在开车,你会知道斑马线是在路面上的、红灯出现的时候车流停下了、鸟会飞在天上。这些物体间的相对关系已经潜移默化地刻在了你的脑子里。在这里,你眼里看到的所有景物就是我上述提到的input,鸟、车流、蓝天、红绿灯则是你抽象出来的pattern,“鸟飞在天上”是你学习到的关于鸟和天的语义信息。综上,对比学习能学习到更多语义丰富的pattern。这些pattern的泛化能力会强于通过监督信号学习到的较为单一的pattern。所以,在大规模的测试集上,对比学习学出来的模型往往效果会更好些。 ## AI 在国内的发展 diff --git a/_posts/MachineLearning/Model/2023-10-30-from_attention_to_transformer.md b/_posts/MachineLearning/Model/2023-10-30-from_attention_to_transformer.md index feb0d5d9..faac3fc5 100644 --- a/_posts/MachineLearning/Model/2023-10-30-from_attention_to_transformer.md +++ b/_posts/MachineLearning/Model/2023-10-30-from_attention_to_transformer.md @@ -345,6 +345,31 @@ $$ 既然不能用矩阵乘法,那用加法,直接把所有的 $x_i$ 加一遍也不是个事儿。从另一个角度,两个向量内积表示表示两个向量的相似度,把$x_1$ 跟其它所有$x_i$ 乘一下,让$y_1=x_1*x_1*x_1 + x_1*x_2*x_2 + x_1*x_{inputlen}*x_{inputlen}$。看样子也挺不错,但这么算,就没啥可学习的W了,这不是$y_i$ 每个加法单元是3个向量相乘嘛,那干脆把$x_i$ 跟一个矩阵wi 变换一下再计算吧,于是有了$W_k$/$W_q$/$W_v$和QKV。 $y_1=Q_1*K_1*V_1 + Q_1*K_2*V_2 + Q_1*K_{inputlen}*V_{inputlen}$。 + +[面试时被问到“Scaling Law”,怎么答?](https://mp.weixin.qq.com/s/Q0fThU-4YP5OwFmfJM_q-Q)对于 Decoder-only 的模型,计算量C(Flops),模型参数量 N(除去 Embedding 部分),数据大小 D(token 数),三者的关系为: C≈6ND。推导如下,记模型的结构为:decoder 层数l,attention隐层维度d,attention feedforward层维度 $d_{ff}$,一般来说 $d_{ff} = 4 * d$。 +模型的参数量N(忽略emebedding、norm和bias) 计算如下,transformer 每层包含 self-attention 和mlp 两个部分 +1. self-attention 的参数为$W_q$、$W_k$、$W_v$、$W_o$,每个矩阵的维度为$R^{d*d}$,整体参数量:$4 * d^2$ +2. mlp 的参数为 $W_1$(维度为$R^{d*d_{ff}}$)和$W_2$(维度为$R^{d_{ff}*d}$),整体参数量:$2 * d * d_ff = 2 * d * 4d = 8d^2$ +3. 所以每层参数是$4d^2 + 8d^2 = 12d^2$,全部l 层的参数量为 $12*ld^2$,即$N=12*ld^2$ + +计算量的单位是FLOPS,float point operations 对于矩阵A (m*n)和B(n*p) AB 相乘的计算量为2mnp,一次加法一次乘法。假设decoder 层的输入X(b*s*d),b为batch size,s为序列长度,d为模型维度。 + +1. 前向推理的计算量: + 1. self-attention 部分的计算: + 1. 输入线性层,$XW_q$、$XW_k$、$XW_v$,计算量为 $3 * b * s * d * d * 2 = 6bsd^2$ + 2. attention 计算 $QK^T$,计算量为 $2 * b * s* s * d = 2bs^2d$ + 3. score 与V 的计算,$S_{attention}V$,计算量为 $b*2 * s * s * d = 2bs^2d$ + 4. 输出线性层 $X^{\prime} W_O$,计算量为 $b * 2 * s * d * d = 2bsd^2$ + 2. MLP 部分的计算: + 1. 升维 $XW_1$,计算量为 $b * 2 * s * d * 4d = 8bsd^2$ + 2. 降维 $XW_2$,计算量为 $b * 2 * s * 4d * d = 8bsd^2$ + 3. 所以整个decoder层的计算量为 $24bsd^2 + 4bs^2d$,全部l层为 $C_{forward}=24bsd^2 + 4bs^2d$。 +2. 反向传播计算量是正向的2倍,所以全部计算量为 $C=3*C_{forward} = 72bsd^2 + 12bs^2d$。 +3. 平均每个token的计算量为 $C_{token}=\frac{C}{b s} = 72ld^2 + 12lsd = 6N (1+\frac{s}{6 d}) \approx 6N(s \le 6d)$ +4. 所以对于包含全部D个token的数据集 $C = C_{token}D \approx 6ND$ + +PS:mlp参数量和计算量都不输attention。 $C_{token} \approx 6N$ 可以认为是正反向3倍*加法乘法2倍=6倍。 + ### 代码 diff --git a/_posts/MachineLearning/Model/2024-10-11-bert.md b/_posts/MachineLearning/Model/2024-10-11-bert.md index 2df83151..6bf26ac8 100644 --- a/_posts/MachineLearning/Model/2024-10-11-bert.md +++ b/_posts/MachineLearning/Model/2024-10-11-bert.md @@ -77,7 +77,7 @@ BERT的论文为我们介绍了几种BERT可以处理的NLP任务: 4. 语义标注 5. 特征提取 ==> rag 里的emebedding -针对不同任务,BERT 采用不同部分的输出做预测,分类任务利用[CLS]位置的 embedding,NER 任务利用每个 token 的输出 embedding。PS:最后一层的输出 选用[cls] 对应的embedding 或多个emebedding 套个FFNN + softmax,二分类或多分类任务就都可以解决了。 +针对不同任务,BERT 采用不同部分的输出做预测,分类任务利用[CLS]位置的 embedding,NER 任务利用每个 token 的输出 embedding。PS:最后一层的输出 选用[cls] 对应的embedding 或多个emebedding 套个FFNN + softmax,二分类或多分类任务就都可以解决了。**可以认为bert 对输入的文本做了一个编码**。 ## 其它 diff --git a/_posts/Technology/CPP/2019-04-19-learn_c.md b/_posts/Technology/CPP/2019-04-19-learn_c.md index ee251395..ccda0ad1 100644 --- a/_posts/Technology/CPP/2019-04-19-learn_c.md +++ b/_posts/Technology/CPP/2019-04-19-learn_c.md @@ -82,7 +82,7 @@ C 语言中经常容易混淆声明和定义这两个概念 头文件的一个重要目的就是为了能够提供一套对外稳定的接口文档,供其他程序使用已经写好的 C 代码实现,以实现代码重用。但为什么其他语言没有借鉴类似的方式,这就说明这种方式并非一种好的设计。[Why are header files bad design? ](https://softwareengineering.stackexchange.com/questions/233484/why-are-header-files-bad-design) -那对于c/cpp来讲呢,最常见到的,头文件和库文件分体设计就是最典型的di,只要是实现了同一个头文件的定义,那么class implementation随时都可以替换。比如我们经常可以通过宏,makefile或者configura.sh发现里面有代码通过判断本地平台是windows还是mac亦或者是linux而加载不同的类实现,而head是不变的。这其实跟java spring context来实现di并无二致,只不过这种注入是编译期发生的。 +那对于c/cpp来讲呢,最常见到的,头文件和库文件分体设计就是最典型的di,只要是实现了同一个头文件的定义,那么class implementation随时都可以替换。比如我们经常可以通过宏,makefile或者configura.sh发现里面有代码通过判断本地平台是windows还是mac亦或者是linux而加载不同的类实现,而head是不变的。这其实跟java spring context来实现di并无二致,只不过这种注入是编译期发生的。[告别头文件,编译效率提升 42%!C++ Modules 实战解析](https://mp.weixin.qq.com/s/1tZYkUIXZNA7g2-OEEFx3g) ## 预处理