专栏名称: 计算机视觉深度学习和自动驾驶
讨论计算机视觉、深度学习和自动驾驶的技术发展和挑战
目录
相关文章推荐
直播海南  ·  南部战区发声! ·  昨天  
中国航务周刊  ·  中远海控首制,国内首艘! ·  3 天前  
直播海南  ·  因违纪提前退伍后,他竟勾连间谍…… ·  3 天前  
51好读  ›  专栏  ›  计算机视觉深度学习和自动驾驶

模型训练 | 大模型-混合专家模型 MoE

计算机视觉深度学习和自动驾驶  · 公众号  ·  · 2024-05-30 00:09

正文

随着 Mixtral 8x7B (announcement, model card)、MoE-LLaVA、Gemini1.5 等 MoE 架构模型的推出,一种称为混合专家模型 (Mixed Expert Models,简称 MoEs) 的 Transformer 模型在开源人工智能社区引起了广泛关注。

随着应用场景的复杂化和细分化,大模型越来越大,垂直领域应用更加碎片化,想要一个模型既能回答通识问题,又能解决专业领域问题,似乎 MoE 是一种性价比更高的选择。MoE 模型由众多小型的“专家”神经网络组成,这些模型可以根据不同的输入类型,学会仅激活最相关的专家网络路径。

开源的混合专家模型列举:

  • • Switch Transformers (Google): 基于 T5 的 MoE 集合,专家数量从 8 名到 2048 名。最大的模型有 1.6 万亿个参数;

  • • OpenMoE: 是开源社区基于 Llama 的模型对 Decoder-only MoE 最早的尝试;

  • • Mixtral 8x7B (Mistral): 一个性能超越了 Llama2-70B 的高质量混合专家模型,并且具有更快的推理速度;

  • • MoE-LLaVA: 北大联合中山大学、腾讯等机构推出的新模型MoE-LLaVA,它仅有3B激活参数,表现却已和7B稠密模型持平,甚至部分指标比13B的模型还要好。

特点

  • • 与稠密模型相比,预训练速度更快;

  • • 与具有相同参数数量的模型相比,具有更快的推理速度;

  • • 需要大量显存,因为所有专家系统都需要加载到内存中;

  • • 在微调方面存在诸多挑战,但近期的研究表明,对混合专家模型进行指令调优具有很大的潜力。

模型架构

混合专家模型(MoE)是一种稀疏门控制的深度学习模型,它主要由一组专家模型和一个门控模型组成。MoE 的基本理念是将输入数据根据任务类型分割成多个区域,并将每个区域的数据分配一个或多个专家模型。每个专家模型可以专注于处理输入这部分数据,从而提高模型的整体性能。

门控网络

GateNet:混合专家模型中“门”是一种稀疏门网络,它接收单个数据元素作为输入,然后输出一个权重,这些权重表示每个专家模型对处理输入数据的贡献。一般是通过 softmax 门控函数通过专家或 token 对概率分布进行建模,并选择前 K 个。例如,如果模型有三个专家,输出的概率可能为 0.5 和 0.4、0.1,这意味着第一个专家对处理此数据的贡献为 50%,第二个专家为 40%,第二个专家为 10%,这个时候的 K 就可以选择为 2,我们认为前两个专家模型的建议会更好,可以用于更加精确的回答中,而第三个专家模型的建议可以用于更加富有创意性的答案中。

专家

Experts:在训练的过程中,输入的数据被门控模型分配到不同的专家模型中进行处理;在推理的过程中,被门控选择的专家会针对输入的数据,产生相应的输出。这些输出最后会和每个专家模型处理该特征的能力分配的权重进行加权组合,形成最终的预测结果。

混合专家模型的实现涉及对专家模型和门控网络的联合训练,在整个数据输入处理的过程中,门控网络起到了动态调配专家模型资源的关键作用,使混合专家模型能够灵活地适应不同的输入数据分布和任务要求。以及在模型结构和参数上的细致调整,以满足具体应用的需求。这种结构允许模型在处理各种输入数据时自适应地选择合适的专家,从而提高模型的表现和效率。

MoE模型代码示例

import torchimport torch.nn as nnimport torch.nn.functional as Ffrom torch.utils.data import DataLoader, Datasetfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_scoreimport numpy as np

# 创建一些随机数据(替换为真实数据)num_samples = 2000num_features = 300 # 假设文本已经转换为固定大小的向量num_classes = 10 # 假设有10个类别
# 随机生成数据和标签X = np.random.randn(num_samples, num_features)y = np.random.randint(0, num_classes, num_samples)
# 划分训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 定义 Datasetclass TextDataset(Dataset): def __init__(self, features, labels): self.features = features self.labels = labels
def __len__(self): return len(self.labels)
def __getitem__(self, idx): return torch.tensor(self.features[idx], dtype=torch.float), torch.tensor(self.labels[idx], dtype=torch.long)

# 创建 DataLoadertrain_dataset = TextDataset(X_train, y_train)train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_dataset = TextDataset(X_test, y_test)test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 模型定义class TopKGating(nn.Module): def __init__(self, input_dim, num_experts, top_k=2): super(TopKGating, self).__init__() # 初始化线性层作为门控机制 self.gate = nn.Linear(input_dim, num_experts) # 设置要选择的顶部专家数量 self.top_k = top_k
def forward(self, x): # 计算每个专家的分数 gating_scores = self.gate(x) # 选取分数最高的 top_k 个专家,并返回它们的索引和 softmax 权重 top_k_values, top_k_indices = torch.topk(F.softmax(gating_scores, dim=1), self.top_k) return top_k_indices, top_k_values

class Expert(nn.Module): def __init__(self, input_dim, output_dim): super(Expert, self).__init__() # 为每个专家定义一个简单的神经网络 self.net = nn.Sequential( nn.Linear(input_dim, 128), nn.ReLU(), nn.Linear(128, output_dim) )
def forward(self, x): # 通过专家网络传递输入数据 return self.net(x)

class MoE(nn.Module): def __init__(self, input_dim, num_classes, num_experts, top_k=2): super(MoE, self).__init__() # 设置专家数量 self.num_experts = num_experts # 设置类别数量 self.num_classes = num_classes # 初始化 TopK 门控层 self.gating = TopKGating(input_dim, num_experts, top_k) # 创建专家网络的列表,每个专家是一个 Expert 实例 self.experts = nn.ModuleList([Expert(input_dim, num_classes) for _ in range(num_experts)])

def forward(self, x): # 获取批量大小 batch_size = x.size(0) # 通过门控层获得 top_k 专家的索引和门控权重 indices, gates = self.gating(x) # 形状 indices:[batch_size, top_k], gates:[batch_size, top_k] # 准备收集选定专家的输出 expert_outputs = torch.zeros(batch_size, indices.size(1), self.num_classes).to(x.device) # 遍历每个样本和其对应的 top_k 专家 for i in range(batch_size): for j in range(indices.size(1)): expert_idx = indices[i, j].item() # 获取专家的索引 expert_outputs[i, j, :] = self.experts[expert_idx](x[i].unsqueeze(0)) # 将门控权重扩展到与专家输出相同的维度 gates = gates.unsqueeze(-1).expand(-1, -1, self.num_classes) # 形状:[batch_size, top_k, num_classes] # 计算加权的专家输出的和 output = (gates * expert_outputs).sum(1) return output, gates.sum(0) # 返回模型输出和门控使用率以用于负载平衡损失计算

def moe_loss(output, target, gating_weights, lambda_balance=0.1): # 标准损失(例如交叉熵损失) # output 是模型的输出,target 是真实的标签 standard_loss = F.cross_entropy(output, target)
# 负载平衡损失 # gating_weights 是门控权重,表示每个专家的使用率 # 使用标准差来衡量各专家使用率的平衡程度 balance_loss = torch.std(gating_weights)
# 总损失






请到「今天看啥」查看全文