阿里推荐算法

一、300. 最长递增子序列(hot100_动态规划_中等)

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        dp = []
        for i in range(len(nums)):
            dp.append(1)
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)

二、160. 相交链表(hot100_链表_简单)

走完两圈后,如果有就是A=B;如果没有A和B都会指向None。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        A, B = headA, headB
        while A != B:
            A = A.next if A else headB
            B = B.next if B else headA
        return A

三、介绍DeepFM模型

见【搜广推校招面经六、七、十一】

import torch
import torch.nn as nn
import torch.optim as optim

class DeepFM(nn.Module):
    def __init__(self, n_features, embedding_dim, hidden_units, dropout_rate=0.5):
        super(DeepFM, self).__init__()
        self.embedding = nn.Embedding(n_features, embedding_dim)
        self.dnn = nn.Sequential(
            nn.Linear(n_features * embedding_dim, hidden_units[0]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_units[0], hidden_units[1]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_units[1], 1)
        )
        
        # 输出层:FM 和 DNN 部分的输出拼接
        self.output_layer = nn.Linear(1 + 1, 1)  # FM 输出与 DNN 输出拼接

    def forward(self, x):
        # FM 部分:计算特征的二阶交互
        embedding_x = self.embedding(x)
        fm_output = torch.sum(torch.pow(torch.sum(embedding_x, dim=1), 2) - torch.sum(torch.pow(embedding_x, 2), dim=1), dim=1, keepdim=True)
        
        # DNN 部分:通过嵌入层和神经网络计算高阶特征交互
        x_dnn = embedding_x.view(embedding_x.size(0), -1)
        dnn_output = self.dnn(x_dnn)

        # 输出层:将 FM 和 DNN 的输出拼接起来
        output = self.output_layer(torch.cat([fm_output, dnn_output], dim=1))
        return output
# 示例
n_features = 10  # 假设有 10 个特征
embedding_dim = 5  # 每个特征的嵌入维度
hidden_units = [64, 32]  # DNN 的隐藏层大小
model = DeepFM(n_features, embedding_dim, hidden_units)
# 假设有 4 个样本,每个样本有 10 个特征
x = torch.randint(0, n_features, (4, n_features))
output = model(x)
print("DeepFM 输出:", output)

四、MMoE如何保证每个专家的随机性(有共用的专家)

MMoE(Multi-gate Mixture-of-Experts) 模型中,多个任务共享一组专家网络(Experts),并通过任务特定的门控机制(Gating Networks)来动态选择专家。为了保证每个专家的随机性(即避免专家之间的冗余或退化),可以从以下几个方面进行设计和优化:

4.1. 专家初始化

  • 随机初始化:每个专家的权重矩阵应使用不同的随机初始化方法(如 Xavier 或 He 初始化),以确保专家之间的初始参数分布不同。
  • 正交初始化:对专家的权重矩阵使用正交初始化,可以进一步减少专家之间的相关性,增强多样性。

4.2. 门控机制的设计

  • Softmax 门控:MMoE 使用 Softmax 门控机制,为每个任务分配不同的专家权重。通过 Softmax 的竞争性,不同任务会倾向于选择不同的专家组合,从而间接保证专家的随机性和多样性。
  • 多任务门控:每个任务有自己的门控网络,独立选择专家。这种设计可以避免任务之间的干扰,同时鼓励专家在不同任务中发挥不同的作用。

4.3. 正则化方法

  • 专家多样性正则化:可以通过正则化方法显式地鼓励专家之间的多样性。例如:
    • 正交正则化:在损失函数中加入专家权重矩阵的正交约束,使得专家的参数空间更加分散。
    • 相关性惩罚:计算专家输出之间的相关性(如余弦相似度),并在损失函数中惩罚高相关性,从而减少专家的冗余。
  • Dropout:在专家网络中引入 Dropout,随机丢弃部分神经元,可以增加模型的随机性,防止专家过度依赖某些特征。

4.4. 任务相关性

  • 任务相关性分析:如果多个任务高度相关,它们可能会倾向于选择相同的专家,导致专家退化。可以通过任务相关性分析(如基于任务梯度的相关性计算)来调整任务权重或门控机制,从而鼓励任务选择不同的专家。
  • 任务特定的损失权重:为不同任务分配不同的损失权重,可以平衡任务之间的竞争,避免某些任务主导专家的选择。

4.5. 动态调整专家容量

  • 专家容量控制:如果某些专家被过度使用(即某些任务总是选择相同的专家),可以通过动态调整专家容量(如限制每个任务选择专家的数量)来强制任务选择其他专家。
  • 专家淘汰机制:在训练过程中,可以监控每个专家的使用频率,如果某些专家长期未被使用,可以重新初始化或替换这些专家。

4.6. 数据增强与噪声注入

  • 输入噪声:在输入数据中加入随机噪声,可以迫使专家学习更鲁棒的特征,从而增加专家的多样性。
  • 数据增强:通过数据增强(如随机裁剪、旋转等)可以增加训练数据的多样性,间接鼓励专家学习不同的特征。

4.7. 训练策略

  • 交替训练:可以交替训练专家和门控网络。例如,先固定门控网络,训练专家;然后固定专家,训练门控网络。这种策略可以避免专家和门控网络之间的耦合过强。
  • 课程学习:逐步增加任务的难度或复杂性,让专家在训练过程中逐步学习不同的特征。

4.8. 专家数量与模型容量

  • 增加专家数量:增加专家的数量可以降低专家之间的竞争压力,从而减少冗余。
  • 控制专家容量:每个专家的容量(如隐藏层大小)不宜过大,否则可能导致专家过度拟合某些任务,降低多样性。

五、Multi-Head Attention 如何保证每个 Head 的随机性(仅通过初始化)

Multi-Head Attention(MHA) 中,每个注意力头(head)负责从不同的子空间中学习特征。为了保证每个头的随机性(即避免所有头学习相同的特征),主要通过 初始化 来实现。

5.1. 随机初始化的关键性

Multi-Head Attention 的每个头的参数(如 Query、Key、Value 的权重矩阵)是独立初始化的。通过随机初始化,可以确保每个头的初始参数分布不同,从而在训练过程中学习到不同的特征。

具体实现

  • 权重矩阵初始化
    • 每个头的 WQW_QWQWKW_KWKWVW_VWV 矩阵使用不同的随机值初始化(如 Xavier 或 He 初始化)。
    • 初始化时,确保不同头的权重矩阵是独立的,避免共享初始化参数。
  • 偏置初始化
    • 偏置项(如果有)也可以使用随机初始化,进一步增强每个头的多样性。

5.2. 其他方式的一些随机性

5.2.1. 多头注意力的结构设计

Multi-Head Attention 的结构本身也支持每个头的独立性:

  • 并行计算:每个头独立计算注意力分数,然后将结果拼接起来。这种并行性确保了每个头可以学习到不同的特征。
  • 子空间投影:每个头将输入投影到不同的子空间中,通过随机初始化,这些子空间的基向量不同,从而捕捉不同的特征。

5.2.2. 训练过程中的随机性

虽然初始化是保证每个头随机性的主要手段,但训练过程中的随机性也会进一步强化每个头的独立性:

  • 梯度更新:每个头的参数在训练过程中会根据不同的梯度更新,从而进一步分化。
  • Dropout:在注意力计算中引入 Dropout,可以增加随机性,防止某些头主导学习过程。

5.2.3. 避免头之间的冗余

如果某些头的学习结果过于相似,可能会导致冗余。可以通过以下方法进一步保证每个头的随机性:

  • 正交初始化:在初始化时,使用正交矩阵初始化权重,使得每个头的投影方向尽可能不同。
  • 正则化:在损失函数中加入正则化项,惩罚头之间的相关性(如余弦相似度)。
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐