用PyTorch从零开始编写DeepSeek-V2

DeepSeek-V2是一个强大的开源混合专家(MoE)语言模型,通过创新的Transformer架构实现了经济高效的训练和推理。该模型总共拥有2360亿参数,其中每个令牌激活21亿参数,支持最大128K令牌的上下文长度。

在开源模型中,DeepSeek-V2实现了顶级性能,成为最强大的开源MoE语言模型。在MMLU(多模态机器学习)上,DeepSeek-V2以较少的激活参数实现了顶尖的性能。与DeepSeek 67B相比,DeepSeek-V2显著提升了性能,降低了42.5%的训练成本,减少了93.3%的KV缓存,并将最大生成吞吐量提高了5.76倍。

我们这里主要实现DeepSeek的主要改进:多头隐性注意力、细粒度专家分割和共享的专家隔离

架构细节

DeepSeek-V2整合了两种创新架构,我们将详细讨论:

  1. 用于前馈网络(FFNs)的DeepSeekMoE架构。
  2. 用于注意力机制的多头隐性注意力(MLA)。

DeepSeekMoE

在标准的MoE架构中,每个令牌被分配给一个(或两个)专家,每个MoE层都有多个在结构上与标准前馈网络(FFN)相同的专家。这种设置带来了两个问题:指定给令牌的专家将试图在其参数中聚集不同类型的知识,但这些知识很难同时利用;其次,被分配给不同专家的令牌可能需要共同的知识,导致多个专家在各自的参数中趋向于收敛,获取共享知识。

为了应对这两个问题,DeepSeekMoE引入了两种策略来增强专家的专业化:

  1. 细粒度专家分割:为了在每个专家中更有针对性地获取知识,通过切分FFN中的中间隐藏维度,将所有专家分割成更细的粒度。
  2. 共享专家隔离:隔离某些专家作为始终被激活的共享专家,旨在捕获不同上下文中的共同知识,并通过将共同知识压缩到这些共享专家中,减少其他路由专家之间的冗余。

让我们来定义DeepSeekMoE中第t个令牌的专家分配。如果u_t是该令牌的FFN输入,其输出h`_t将会是:

其中𝑁𝑠和𝑁𝑟分别是共享专家和路由专家的数量;FFN(𝑠)*𝑖和FFN(𝑟)*𝑖分别表示𝑖-th共享专家和𝑖-th路由专家。

对于路由专家而言,g_i,t 是第i个路由专家的门控值,s_i,t 是令牌到专家的亲和分数,Topk(., Kr) 包含了Kr个最高的亲和分数,其中Kr是活跃的路由专家的数量。

有了以上的公式,我们就来使用代码实现

门控模型实现:

 classMoEGate(torch.nn.Module):def__init__(self, num_experts_per_tok: int, n_routed_experts: int, routed_scaling_factor: int, topk_method: str, n_group: int, topk_group: int, hidden_size: int):super().__init__()self.top_k=num_experts_per_tokself.n_routed_experts=n_routed_expertsself.routed_scaling_factor=routed_scaling_factorself.topk_method=topk_methodself.n_group=n_groupself.topk_group=topk_groupself.weight=torch.nn.Parameter(torch.empty((self.n_routed_experts, hidden_size)))torch.nn.init.kaiming_uniform_(self.weight, a=math.sqrt(5))defforward(self, x: torch.Tensor):batch, seq_len, h=x.shapehidden_states=x.view(-1, h)logits=torch.nn.functional.linear(hidden_states.type(torch.float32), self.weight.type(torch.float32), None)scores=logits.softmax(dim=-1, dtype=torch.float32)ifself.topk_method=="greedy":topk_weight, topk_idx=torch.topk(scores, k=self.top_k, dim=-1, sorted=False)elifself.topk_method=="group_limited_greedy":group_scores= (scores.view(batch*seq_len, self.n_group, -1).max(dim=-1).values)group_idx=torch.topk(group_scores, k=self.topk_group, dim=-1, sorted=False)[1]  # [n, top_k_group]group_mask=torch.zeros_like(group_scores)  # [n, n_group]group_mask.scatter_(1, group_idx, 1)  # [n, n_group]score_mask= (group_mask.unsqueeze(-1).expand(batch*seq_len, self.n_group, self.n_routed_experts//self.n_group).reshape(batch*seq_len, -1))  # [n, e]tmp_scores=scores.masked_fill(~score_mask.bool(), 0.0)  # [n, e]topk_weight, topk_idx=torch.topk(tmp_scores, k=self.top_k, dim=-1, sorted=False)returntopk_idx, topk_weight

MoE

 classMoE(torch.nn.Module):def__init__(self, dim: int, routed_scaling_factor: int, topk_method: str, n_group: int, topk_group: int, hidden_dim: int|None=None, n_routed_experts: int=12, num_experts_per_tok: int=4, n_shared_experts: int=2, mlp: str="swiglu"):super().__init__()self.experts_per_rank=n_routed_expertsself.num_experts_per_tok=num_experts_per_tokself.n_shared_experts=n_shared_expertsmlp_block=SwiGLUself.experts=torch.nn.ModuleList([mlp_block(dim, hidden_dim) foriinrange(n_routed_experts)])self.gate=MoEGate(num_experts_per_tok, n_routed_experts, routed_scaling_factor, topk_method, n_group, topk_group, dim)self.shared_experts=mlp_block(dim, hidden_dim*n_shared_experts)defforward(self, x: torch.Tensor):identity=xorig_shape=x.shapetopk_idx, topk_weight=self.gate(x)x=x.view(-1, x.shape[-1])flat_topk_idx=topk_idx.view(-1)x=x.repeat_interleave(self.num_experts_per_tok, dim=0)y=torch.empty_like(x)y=y.type(x.dtype)fori, expertinenumerate(self.experts):y[flat_topk_idx==i] =expert(x[flat_topk_idx==i]).to(dtype=x.dtype)y= (y.view(*topk_weight.shape, -1) *topk_weight.unsqueeze(-1)).sum(dim=1)y=y.view(*orig_shape)output=y+self.shared_experts(identity)returnoutput

多头隐性注意力(MLA)

多头隐性注意力(MLA)相较于标准的多头注意力(MHA)实现了更优的性能,并且显著减少了KV缓存,提高了推理效率。与多查询注意力(MQA)和分组查询注意力(GQA)中减少KV头的方法不同,MLA将键(Key)和值(Value)共同压缩成一个潜在向量。

MLA不是缓存键(Key)和值(Value)矩阵,而是将它们联合压缩成一个低秩向量,这使得缓存的项目数量更少,因为压缩维度远小于多头注意力(MHA)中输出投影矩阵的维度。

标准的RoPE(旋转位置嵌入)与上述的低秩KV压缩不兼容。解耦RoPE策略使用额外的多头查询q_t和共享键k_t来实现RoPE。

下面总结了完整的MLA计算过程:

MLA实现

 classMLA(torch.nn.Module):def__init__(self, model_args: DeepseekConfig):super().__init__()d_model=model_args.d_modelself.num_heads=model_args.num_headsself.head_dim=model_args.d_model//model_args.num_headsself.attn_dropout=torch.nn.Dropout(model_args.dropout)self.res_dropout=torch.nn.Dropout(model_args.dropout)self.flash_attn=hasattr(torch.nn.functional, "scaled_dot_product_attention")self.q_lora_rank=model_args.q_lora_rankself.qk_rope_head_dim=model_args.qk_rope_head_dimself.kv_lora_rank=model_args.kv_lora_rankself.v_head_dim=model_args.v_head_dimself.qk_nope_head_dim=model_args.qk_nope_head_dimself.q_head_dim=model_args.qk_nope_head_dim+model_args.qk_rope_head_dimself.q_a_proj=torch.nn.Linear(d_model, model_args.q_lora_rank, bias=False)self.q_a_layernorm=RMSNorm(model_args.q_lora_rank)self.q_b_proj=torch.nn.Linear(model_args.q_lora_rank, self.num_heads*self.q_head_dim, bias=False)self.kv_a_proj_with_mqa=torch.nn.Linear(d_model,model_args.kv_lora_rank+model_args.qk_rope_head_dim,bias=False,)self.kv_a_layernorm=RMSNorm(model_args.kv_lora_rank)self.kv_b_proj=torch.nn.Linear(model_args.kv_lora_rank,self.num_heads* (self.q_head_dim-self.qk_rope_head_dim+self.v_head_dim),bias=False,)self.o_proj=torch.nn.Linear(self.num_heads*self.v_head_dim,d_model, bias=False,)defforward(self, x: torch.Tensor, mask: torch.Tensor, freqs_cis) ->torch.Tensor:batch, seq_len, d_model=x.shapeq=self.q_b_proj(self.q_a_layernorm(self.q_a_proj(x)))q=q.view(batch, seq_len, self.num_heads, self.q_head_dim).transpose(1, 2)q_nope, q_pe=torch.split(q, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1)compressed_kv=self.kv_a_proj_with_mqa(x)compressed_kv, k_pe=torch.split(compressed_kv, [self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)k_pe=k_pe.view(batch, seq_len, 1, self.qk_rope_head_dim).transpose(1, 2)kv= (self.kv_b_proj(self.kv_a_layernorm(compressed_kv)).view(batch, seq_len, self.num_heads, self.qk_nope_head_dim+self.v_head_dim).transpose(1, 2))k_nope, value_states=torch.split(kv, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)q_pe, k_pe=apply_rope(q_pe, k_pe, freqs_cis)k_pe=k_pe.transpose(2, 1)q_pe=q_pe.transpose(2, 1)query_states=k_pe.new_empty(batch, self.num_heads, seq_len, self.q_head_dim)query_states[:, :, :, : self.qk_nope_head_dim] =q_nopequery_states[:, :, :, self.qk_nope_head_dim :] =q_pekey_states=k_pe.new_empty(batch, self.num_heads, seq_len, self.q_head_dim)key_states[:, :, :, : self.qk_nope_head_dim] =k_nopekey_states[:, :, :, self.qk_nope_head_dim :] =k_peattn_mtx=torch.matmul(query_states, key_states.transpose(2, 3)) /math.sqrt(self.head_dim)attn_mtx=attn_mtx+mask[:, :, :seq_len, :seq_len]attn_mtx=torch.nn.functional.softmax(attn_mtx.float(), dim=-1).type_as(key_states)attn_mtx=self.attn_dropout(attn_mtx)output=torch.matmul(attn_mtx, value_states)  # (batch, n_head, seq_len, head_dim)output=output.transpose(1, 2).contiguous().view(batch, seq_len, self.num_heads*self.v_head_dim)output=self.o_proj(output)output=self.res_dropout(output)returnoutput

总结

本文详细介绍了DeepSeek-V2语言模型,这是一个强大的开源混合专家(MoE)语言模型,采用创新的架构来提高训练和推理的经济性和效率。DeepSeek-V2采用了两种核心技术:细粒度专家分割和共享专家隔离,这两种策略显著提高了专家的专业化水平。此外,文章还介绍了多头隐性注意力(MLA),这是一种改进的注意力机制,通过低秩键值联合压缩和解耦旋转位置嵌入,优化了模型的存储和计算效率。

除了理论探讨,我们通过编写代码实现DeepSeek-V2,可以更深入地理解其架构和工作原理。可以帮助你账务如何实现先进的混合专家(MoE)模型,还能深化对多头隐性注意力(MLA)和低秩键值压缩等关键技术的理解。通过实践,读者将能够验证理论的有效性,并对模型的性能和效率有直观的认识。

https://avoid.overfit.cn/post/317a967c8dac42ee98f96d8390851476

作者:Zain ul Abideen

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3前端开发-小兔鲜项目-一些额外提醒的内容

vue3前端开发-小兔鲜项目-一些额外提醒的内容!今天这一篇文章,是提醒大家,如果你正在学习小兔鲜这个前端项目,有些地方需要提醒大家,额外注意的地方。 第一个:就是大家在进入二级页面后,有一个分…

深度学习-7-使用DCGAN生成动漫头像(实战)

参考什么是GAN生成对抗网络,使用DCGAN生成动漫头像 1 什么是生成对抗网络 生成对抗网络,英文是Generative Adversarial Networks,简称GAN。 GAN是一种无监督的深度学习模型,于2014年首次被提出。该算法通过竞争学习的方式生成新的、且与原始数据集相似的数据。 这些生成…

昇思25天学习打卡营第19天|生成式-DCGAN生成漫画头像

打卡 目录 打卡 GAN基础原理 DCGAN原理 案例说明 数据集操作 数据准备 数据处理和增强 部分训练数据的展示 构造网络 生成器 生成器代码 ​编辑 判别器 判别器代码 模型训练 训练代码 结果展示(3 epoch) 模型推理 GAN基础原理 原理介…

C#实战 | 天行健、上下而求索

本文介绍C#开发入门案例。 01、项目一:创建控制台应用“天行健,君子以自强不息” 项目说明: 奋斗是中华民族的底色,见山开山,遇水架桥,正是因为自强不息的奋斗,才有了辉煌灿烂的中华民族。今…

xmind--如何快速将Excel表中多列数据,复制到XMind分成多级主题

每次要将表格中的数据分成多级时,只能复制粘贴吗 快来试试这个简易的方法吧 这个是原始的表格,分成了4级 步骤: 1、我们可以先按照这个层级设置下空列(后买你会用到这个空列) 二级不用加、三级前面加一列、四级前面加…

MAT使用

概念 Shallow heap & Retained Heap Shallow Heap就是对象本身占用内存的大小。 Retained Heap就是当前对象被GC后,从Heap上总共能释放掉的内存(表示如果一个对象被释放掉,那会因为该对象的释放而减少引用进而被释放的所有的对象(包括…

【React】JSX 实现列表渲染

文章目录 一、基础语法1. 使用 map() 方法2. key 属性的使用 二、常见错误和注意事项1. 忘记使用 key 属性2. key 属性的选择 三、列表渲染的高级用法1. 渲染嵌套列表2. 条件渲染列表项3. 动态生成组件 四、最佳实践 在 React 开发中,列表渲染是一个非常常见的需求。…

【多模态】CLIP-KD: An Empirical Study of CLIP Model Distillation

论文:CLIP-KD: An Empirical Study of CLIP Model Distillation 链接:https://arxiv.org/pdf/2307.12732 CVPR 2024 Introduction Motivation:使用大的Teacher CLIP模型有监督蒸馏小CLIP模型,出发点基于在资源受限的应用中&…

【网络】tcp_socket

tcp_socket 一、tcp_server与udp_server一样的部分二、listen接口(监听)三、accept接收套接字1、为什么还要多一个套接字(明明已经有了个socket套接字文件了,为什么要多一个accept套接字文件?)2、底层拿到新…

从R-CNN到Faster-R-CNN的简单介绍

1、R-CNN RCNN算法4个步骤 1、一张图像生成1K~2K个候选区域(使用Selective Search方法) 2、对每个候选区域,使用深度网络提取特征 3、特征送入每一类的SVM分类器,判别是否属于该类 4、使用回归器精细修正候选框位置 R-CNN 缺陷 : 1.训练…

Java使用AsposePDF和AsposeWords进行表单填充

声明:本文为作者Huathy原创文章,禁止转载、爬取!否则,本人将保留追究法律责任的权力! 文章目录 AsposePDF填充表单adobe pdf表单准备引入依赖编写测试类 AsposeWord表单填充表单模板准备与生成效果引入依赖编码 参考文…

【C语言】链式队列的实现

队列基本概念 首先我们要了解什么是队列,队列里面包含什么。 队列是线性表的一种是一种先进先出(First In Fi Out)的数据结构。在需要排队的场景下有很强的应用性。有数组队列也有链式队列,数组实现的队列时间复杂度太大&#x…

【数据结构 | 哈希表】一文了解哈希表(散列表)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

虚拟局域网配置与分析-VLAN

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、相关知识 虚拟局域网(Virtual Local Area Network,VLAN)是一组逻辑上的设备和用户;不受物理位置的…

浅谈监听器之保存响应到文件

浅谈监听器之保存响应到文件 JMeter 提供了一个实用的监听器——“保存响应到文件”,该监听器能够自动将取样器的响应数据直接保存到指定的文件中,便于后续分析或存档。本文档旨在详细介绍如何配置和使用此监听器功能。 适用场景 ● 长时间运行的测试…

昇思25天学习打卡营第n天|本地安装mindspore之二|开始第一课的代码。以及对比xshell,MobaXterm

开始准备在本地的系统上跑例子了。从第一课开始吧。 1,下载代码 打开课程。 下载样例代码 https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r2.3/tutorials/zh_cn/beginner/mindspore_quick_start.py 2,在本地Linux上输入并运…

Python新手如何制作植物大战僵尸?这篇文章教会你!

引言 《植物大战僵尸》是一款非常受欢迎的塔防游戏,玩家需要种植各种植物来抵御僵尸的进攻。在这篇文章中,我们将使用Python编写一个简化版的植物大战僵尸游戏,以展示如何使用Python创建游戏。 游戏规则 玩家将种植不同类型的植物来防御僵尸…

好用的电脑录屏软件免费推荐,拥有这3款就能高效录屏!

电脑录屏软件已成为我们记录生活、分享知识的得力助手。但是,市面上琳琅满目的录屏软件令人眼花缭乱,如何才能选择到一款好用的电脑录屏软件免费神器呢?今天,就让我来为您揭晓这个秘密! 首先,我们得明确一…

胖东来也要加入“打水仗”?瓶装水品牌又该如何出招

今年瓶装水行业的“战场”似乎格外热闹,比武汉的天气好像还要火热......从年头农夫山泉打出“纯净水”的牌,再到如今掀起价格内卷战,一箱12瓶的纯净水在某宝平台上仅售9.9元,平均下来每瓶单价不超一元,农夫山泉都出击了…

自动化网络爬虫:如何它成为提升数据收集效率的终极武器?

摘要 本文深入探讨了自动化网络爬虫技术如何彻底改变数据收集领域的游戏规则,揭示其作为提升工作效率的终极工具的奥秘。通过分析其工作原理、优势及实际应用案例,我们向读者展示了如何利用这一强大工具加速业务决策过程,同时保持数据收集的…