图神经网络分享系列-HAN(Heterogeneous Graph Attention Network)(三)

目录

一、模型

1、对比

[1、GAT- 标准图注意力网络](#1、GAT- 标准图注意力网络)

[2、HeteGAT_multi( HAN核心模型(当前使用的)](#2、HeteGAT_multi( HAN核心模型(当前使用的))

[2.1 attn_head:节点级别注意力](#2.1 attn_head:节点级别注意力)

[2.2 SimpleAttLayer:语义级别注意力](#2.2 SimpleAttLayer:语义级别注意力)

3、HeteGAT_no_coef

4、HeteGAT


图神经网络概览:图神经网络分享系列-概览

上一篇文章:图神经网络分享系列-HAN(Heterogeneous Graph Attention Network)(二)

本章内容主要进行实战

github 链接:https://github.com/Jhy1993/HAN

一、模型

1、对比

模型 元路径注意力 节点注意力系数 用途
GAT 同构图/作为基础组件
HeteGAT_multi 异构图分类(当前使用)
HeteGAT_no_coef 轻量级异构图分类
HeteGAT ✅(可选) 异构图分类 + 可解释性分析

GAT:

输入 → [注意力] → 输出

HeteGAT_multi/HeteGAT_no_coef:

输入1 → [节点注意力] → 嵌入1

输入2 → [节点注意力] → 嵌入2

语义注意力\] → 输出 HeteGAT: 输入1 → \[节点注意力(含系数)\] → 嵌入1 输入2 → \[节点注意力(含系数)\] → 嵌入2 ↓ \[语义注意力\] → 输出 ↓ 可选返回节点级注意力系数

1、GAT- 标准图注意力网络

这个部分之前分享过,本次不做过多赘述,可参考:

图神经网络分享系列-GAT(GRAPH ATTENTION NETWORKS) (四)-实战篇

python 复制代码
class GAT(BaseGAttN):
    """
    GAT (Graph Attention Network) - 标准同构图注意力网络

    这是一个基础的GAT实现,用于处理单一类型节点的同构图。
    在HAN中,我们使用多个GAT分别处理不同的元路径。

    架构:
        输入特征 → 多头注意力层 → 输出层 → 分类结果
    """

    def inference(inputs, nb_classes, nb_nodes, training, attn_drop, ffd_drop,
                  bias_mat, hid_units, n_heads, activation=tf1.nn.elu, residual=False):
        """
        GAT前向传播

        参数:
            inputs: 节点特征 [batch_size, nb_nodes, feature_size]
            nb_classes: 分类类别数
            nb_nodes: 节点数量
            training: 是否训练模式
            attn_drop: 注意力系数dropout率
            ffd_drop: 前馈层dropout率
            bias_mat: 邻接矩阵偏置
            hid_units: 隐藏层单元数列表
            n_heads: 注意力头数列表
            activation: 激活函数
            residual: 是否使用残差连接

        返回:
            logits: 分类logits
        """
        attns = []
        # 第一层:多头注意力
        for _ in range(n_heads[0]):
            attns.append(layers.attn_head(inputs, bias_mat=bias_mat,
                                          out_sz=hid_units[0], activation=activation,
                                          in_drop=ffd_drop, coef_drop=attn_drop, residual=False))
        # 拼接多头输出
        h_1 = tf1.concat(attns, axis=-1)

        # 后续层(如果有的话)
        for i in range(1, len(hid_units)):
            h_old = h_1
            attns = []
            for _ in range(n_heads[i]):
                attns.append(layers.attn_head(h_1, bias_mat=bias_mat,
                                              out_sz=hid_units[i], activation=activation,
                                              in_drop=ffd_drop, coef_drop=attn_drop, residual=residual))
            h_1 = tf1.concat(attns, axis=-1)

        # 输出层
        out = []
        for i in range(n_heads[-1]):
            out.append(layers.attn_head(h_1, bias_mat=bias_mat,
                                        out_sz=nb_classes, activation=lambda x: x,
                                        in_drop=ffd_drop, coef_drop=attn_drop, residual=False))
        logits = tf1.add_n(out) / n_heads[-1]

        return logits

2、HeteGAT_multi( HAN核心模型(当前使用的)

python 复制代码
class HeteGAT_multi(BaseGAttN):
    """
    HeteGAT_multi - HAN的核心模型(多注意力头版本)

    这是HAN的主要实现,包含双层注意力机制:

    1. 节点级注意力 (Node-level Attention):
       - 对每个元路径分别应用多头注意力机制
       - 学习如何聚合同一元路径下邻居节点的信息

    2. 语义级注意力 (Semantic Attention):
       - 使用SimpleAttLayer融合不同元路径的嵌入
       - 自动学习每个元路径的重要性权重

    示例(ACM数据集):
        - 元路径1: PAP (Paper-Author-Paper) - 通过作者连接的论文
        - 元路径2: PLP (Paper-Label-Paper) - 通过标签连接的论文
    """

    def inference(inputs_list, nb_classes, nb_nodes, training, attn_drop, ffd_drop,
                  bias_mat_list, hid_units, n_heads, activation=tf1.nn.elu, residual=False,
                  mp_att_size=128):
        """
        HAN前向传播

        参数:
            inputs_list: 多个元路径的节点特征列表
                         每个元素形状: [batch_size, nb_nodes, feature_size]
            nb_classes: 分类类别数
            nb_nodes: 节点数量
            training: 是否训练模式
            attn_drop: 注意力系数dropout率 (训练时设为0.6,推理时设为0)
            ffd_drop: 前馈层dropout率 (训练时设为0.6,推理时设为0)
            bias_mat_list: 多个元路径的邻接矩阵偏置列表
                           每个元素形状: [batch_size, nb_nodes, nb_nodes]
            hid_units: 隐藏层单元数列表, 如 [8] 表示一层8个隐藏单元
            n_heads: 注意力头数列表, 如 [8, 1] 表示第一层8个头,输出层1个头
            activation: 激活函数 (默认ELU)
            residual: 是否使用残差连接
            mp_att_size: 元路径注意力层的大小 (默认128)

        返回:
            logits: 节点分类logits, 形状 [batch_size, nb_nodes, nb_classes]
            final_embed: 最终的节点嵌入, 形状 [batch_size, nb_nodes, hidden_dim]
            att_val: 元路径注意力权重, 形状 [batch_size, num_meta_paths]
        """
        embed_list = []  # 存储每个元路径的嵌入

        # =================================================================
        # 第一层:节点级注意力 (Node-level Attention)
        # =================================================================
        # 对每个元路径分别进行处理
        for inputs, bias_mat in zip(inputs_list, bias_mat_list):
            # inputs: 节点特征 [batch, nb_nodes, ft_size]
            # bias_mat: 邻接矩阵的偏置 [batch, nb_nodes, nb_nodes]
            attns = []
            jhy_embeds = []

            # 多头注意力机制 (Multi-Head Attention)
            # n_heads[0]=8,表示使用8个注意力头
            # 每个头学习不同的注意力权重
            for _ in range(n_heads[0]):
                # 对每个元路径分别做注意力卷积
                # attn_head函数实现了GAT的核心注意力机制
                attns.append(layers.attn_head(inputs, bias_mat=bias_mat,
                                              out_sz=hid_units[0], activation=activation,
                                              in_drop=ffd_drop, coef_drop=attn_drop, residual=False))

            # 拼接多头输出
            # 形状: [batch, nb_nodes, hid_units[0] * n_heads[0]] = [1, N, 64]
            h_1 = tf1.concat(attns, axis=-1)

            # 如果有更多隐藏层,继续处理
            for i in range(1, len(hid_units)):
                h_old = h_1
                attns = []
                for _ in range(n_heads[i]):
                    attns.append(layers.attn_head(h_1, bias_mat=bias_mat,
                                                  out_sz=hid_units[i],
                                                  activation=activation,
                                                  in_drop=ffd_drop,
                                                  coef_drop=attn_drop, residual=residual))
                h_1 = tf1.concat(attns, axis=-1)

            # 将该元路径的嵌入添加到列表
            # 形状调整: [batch, nb_nodes, hidden_dim] -> [batch, 1, nb_nodes, hidden_dim]
            embed_list.append(tf1.expand_dims(tf1.squeeze(h_1), axis=1))

        # =================================================================
        # 第二层:语义级注意力 (Semantic Attention)
        # =================================================================
        # 将多个元路径的嵌入拼接
        # 形状: [batch, num_mp, nb_nodes, hidden_dim]
        multi_embed = tf1.concat(embed_list, axis=1)

        # 使用SimpleAttLayer对元路径进行加权融合
        # 这是一个可学习的注意力机制,自动学习每个元路径的重要性
        # mp_att_size=128 是注意力层的隐藏维度
        final_embed, att_val = layers.SimpleAttLayer(multi_embed, mp_att_size,
                                                     time_major=False,
                                                     return_alphas=True)

        # =================================================================
        # 输出层
        # =================================================================
        out = []
        for i in range(n_heads[-1]):
            # 使用全连接层进行分类
            # 这里可以继续使用注意力头,或者直接用dense层
            out.append(tf1.layers.dense(final_embed, nb_classes, activation=None))

        # 取平均(如果有多个注意力头)
        logits = tf1.add_n(out) / n_heads[-1]

        print('de')  # 调试输出

        # 调整输出形状以匹配标签格式
        logits = tf1.expand_dims(logits, axis=0)

        # 返回: logits, 最终嵌入, 元路径注意力权重
        return logits, final_embed, att_val

2.1 attn_head:节点级别注意力

python 复制代码
def attn_head(seq, out_sz, bias_mat, activation, in_drop=0.0, coef_drop=0.0, residual=False,
              return_coef=False):
    """
    attn_head - 节点级注意力层 (Node-level Attention)

    这是GAT的核心实现,实现了对邻居节点的信息聚合。
    核心思想是:不同邻居节点对目标节点的贡献是不同的,通过注意力机制学习这种重要性差异。

    注意力机制计算流程:
        1. 特征变换: 将输入特征通过线性层映射到低维空间
        2. 注意力分数计算: 使用LeakyReLU激活函数计算节点对之间的注意力分数
        3. 掩码操作: 通过邻接矩阵掩码,屏蔽非邻居节点
        4. Softmax归一化: 将注意力分数归一化为概率分布
        5. 特征聚合: 使用注意力系数对邻居特征进行加权求和

    参数:
        seq: 输入序列/节点特征
             形状: [batch_size, nb_nodes, feature_size]
             例如: [1, 3025, 1870] 表示3025个节点,每个节点1870维特征
        out_sz: 输出特征维度
                如果hid_units[0]=8, n_heads[0]=8,则输出维度为8*8=64
        bias_mat: 邻接矩阵偏置
                  形状: [batch_size, nb_nodes, nb_nodes]
                  用于屏蔽非邻居节点,非邻居位置为-1e9,邻居位置为0
        activation: 激活函数 (通常使用ELU)
        in_drop: 输入特征的dropout率 (训练时使用,推理时为0)
        coef_drop: 注意力系数的dropout率 (训练时使用,推理时为0)
        residual: 是否使用残差连接
        return_coef: 是否返回注意力系数 (用于可视化和分析)

    返回:
        activation(ret): 经过激活函数处理的聚合特征
                        形状: [batch_size, nb_nodes, out_sz]
        coefs: 注意力系数 (可选,只有return_coef=True时返回)
               形状: [batch_size, nb_nodes, nb_nodes]

    示例:
        假设节点A有两个邻居B和C
        - 注意力系数 α_AB = 0.7, α_AC = 0.3
        - 节点A的新表示 = 0.7 * W·h_B + 0.3 * W·h_C
    """
    with tf1.name_scope('my_attn'):
        # =================================================================
        # 步骤1: 输入Dropout
        # =================================================================
        # 在训练时随机丢弃部分输入特征,防止过拟合
        if in_drop != 0.0:
            seq = tf1.nn.dropout(seq, 1.0 - in_drop)

        # =================================================================
        # 步骤2: 特征变换
        # =================================================================
        # 使用1x1卷积(等价于线性变换)对输入特征进行映射
        # 将特征从 ft_size 维映射到 out_sz 维
        # seq_fts形状: [batch, nb_nodes, out_sz]
        seq_fts = tf1.layers.conv1d(seq, out_sz, 1, use_bias=False)

        # =================================================================
        # 步骤3: 计算注意力分数
        # =================================================================
        # 使用两个独立的线性变换 f_1 和 f_2
        # 将特征映射到1维,得到注意力分数
        # 这允许模型学习不同的"查询"和"键"
        f_1 = tf1.layers.conv1d(seq_fts, 1, 1)  # 形状: [batch, nb_nodes, 1]
        f_2 = tf1.layers.conv1d(seq_fts, 1, 1)  # 形状: [batch, nb_nodes, 1]

        # =================================================================
        # 步骤4: 计算节点对之间的注意力分数
        # =================================================================
        # logits[i][j] 表示节点i对节点j的注意力分数
        # 通过 f_1 + f_2^T 实现: a^T [W·h_i || W·h_j]
        # 这种方式是GAT论文中推荐的做法,比直接拼接更高效
        # transpose: [1, 3, 1] -> [1, 1, 3]
        # 相加后: [1, 3, 1] + [1, 1, 3] -> [1, 3, 3]
        logits = f_1 + tf1.transpose(f_2, [0, 2, 1])
        # logits形状: [batch, nb_nodes, nb_nodes]

        # =================================================================
        # 步骤5: LeakyReLU激活 + 邻接矩阵掩码 + Softmax
        # =================================================================
        # LeakyReLU: 允许负值存在但梯度较小,常用于注意力机制
        # bias_mat: 邻接矩阵偏置,非邻居位置为-1e9,邻居位置为0
        # Softmax: 将每个节点的注意力分数归一化为概率分布
        coefs = tf1.nn.softmax(tf1.nn.leaky_relu(logits) + bias_mat)
        # coefs形状: [batch, nb_nodes, nb_nodes]
        # coefs[i][j] 表示节点i对节点j的注意力权重

        # =================================================================
        # 步骤6: 注意力系数Dropout
        # =================================================================
        # 训练时随机丢弃部分注意力连接,增加模型鲁棒性
        if coef_drop != 0.0:
            coefs = tf1.nn.dropout(coefs, 1.0 - coef_drop)

        # 特征Dropout(第二次)
        if in_drop != 0.0:
            seq_fts = tf1.nn.dropout(seq_fts, 1.0 - in_drop)

        # =================================================================
        # 步骤7: 特征聚合
        # =================================================================
        # 使用注意力系数对邻居特征进行加权求和
        # vals[i][j] = Σ(coefs[i][j] * seq_fts[j])
        # 即:节点i的新表示 = Σ(注意力权重 × 邻居节点特征)
        vals = tf1.matmul(coefs, seq_fts)
        # vals形状: [batch, nb_nodes, out_sz]

        # TF2.x兼容:移除bias_add,直接使用vals
        ret = vals

        # =================================================================
        # 步骤8: 残差连接 (可选)
        # =================================================================
        # 残差连接有助于深层网络的训练
        # 如果输出维度与输入维度相同,则直接相加
        # 否则,通过线性变换后再相加
        if residual:
            if seq.shape[-1] != ret.shape[-1]:
                ret = ret + conv1d(seq, ret.shape[-1], 1)  # 激活
            else:
                seq_fts = ret + seq

        # =================================================================
        # 返回结果
        # =================================================================
        if return_coef:
            # 同时返回聚合特征和注意力系数(用于分析)
            return activation(ret), coefs
        else:
            # 只返回聚合特征
            return activation(ret)

2.2 SimpleAttLayer:语义级别注意力

python 复制代码
def SimpleAttLayer(inputs, attention_size, time_major=False, return_alphas=False):
    """
    SimpleAttLayer - 语义级注意力层 (Semantic Attention)

    这是HAN中第二层注意力机制,用于融合不同元路径的嵌入表示。

    核心思想:
        不同元路径对于下游任务的贡献是不同的,
        通过可学习的注意力机制自动学习每个元路径的重要性权重。

    例如在ACM数据集中:
        - PAP (Paper-Author-Paper): 通过作者连接的论文
        - PLP (Paper-Label-Paper): 通过标签连接的论文

        模型会学习到:对于论文分类任务,PLP路径可能比PAP路径更重要

    注意力机制计算流程:
        1. 将输入通过一个带激活的全连接层
        2. 计算每个元路径的注意力分数
        3. 通过Softmax归一化
        4. 使用归一化的权重对输入进行加权求和

    参数:
        inputs: 多个元路径的嵌入
                形状: [batch_size, num_meta_paths, nb_nodes, hidden_dim]
                例如: [1, 2, 3025, 64] 表示2个元路径,3025个节点,64维嵌入
        attention_size: 注意力层的隐藏维度
                       用于计算注意力分数的中间维度,默认128
        time_major: 是否时间序列优先(此场景固定为False)
        return_alphas: 是否返回注意力权重(用于分析)

    返回:
        output: 融合后的嵌入
                形状: [batch_size, nb_nodes, hidden_dim]
        alphas: 注意力权重 (可选)
                形状: [batch_size, num_meta_paths]
                表示每个元路径的重要性

    示例:
        假设有2个元路径:
        - 嵌入1: PAP路径的表示, shape [1, 3025, 64]
        - 嵌入2: PLP路径的表示, shape [1, 3025, 64]

        SimpleAttLayer会学习权重:
        - α_1 = 0.3 (PAP的重要性)
        - α_2 = 0.7 (PLP的重要性)

        最终嵌入 = 0.3 × 嵌入1 + 0.7 × 嵌入2
    """

    # 如果输入是元组(双向RNN等情况),进行拼接
    if isinstance(inputs, tuple):
        inputs = tf1.concat(inputs, 2)

    # 时间序列优先时的维度转换(此场景不使用)
    if time_major:
        inputs = tf1.transpose(inputs, [1, 0, 2])

    # 获取输入的隐藏维度
    hidden_size = inputs.shape[2].value  # D value - hidden size

    # =================================================================
    # 可学习的注意力参数
    # =================================================================
    # w_omega: 将输入映射到注意力空间的权重矩阵
    # 形状: [hidden_dim, attention_size]
    # 例如: [64, 128]
    w_omega = tf1.Variable(tf1.random_normal([hidden_size, attention_size], stddev=0.1))

    # b_omega: 注意力空间的偏置
    # 形状: [attention_size]
    b_omega = tf1.Variable(tf1.random_normal([attention_size], stddev=0.1))

    # u_omega: 用于计算注意力权重的向量
    # 形状: [attention_size]
    u_omega = tf1.Variable(tf1.random_normal([attention_size], stddev=0.1))

    # =================================================================
    # 计算注意力分数
    # =================================================================
    # 第一步:将输入映射到注意力空间
    # v = tanh(W·h + b)
    # v形状: [batch, num_mp, attention_size]
    with tf1.name_scope('v'):
        v = tf1.tanh(tf1.tensordot(inputs, w_omega, axes=1) + b_omega)

    # 第二步:计算每个元路径的注意力分数
    # vu = v · u^T
    # vu形状: [batch, num_mp]
    # 这是一个标量分数,表示每个元路径的"重要性"
    vu = tf1.tensordot(v, u_omega, axes=1, name='vu')

    # 第三步:Softmax归一化
    # alphas形状: [batch, num_mp]
    # 每个元路径的注意力权重,归一化为概率分布
    alphas = tf1.nn.softmax(vu, name='alphas')

    # =================================================================
    # 加权求和
    # =================================================================
    # output = Σ(α_i × h_i)
    # 使用注意力权重对输入进行加权求和
    # output形状: [batch, hidden_dim]
    output = tf1.reduce_sum(inputs * tf1.expand_dims(alphas, -1), 1)

    # =================================================================
    # 返回结果
    # =================================================================
    if not return_alphas:
        return output
    else:
        # 同时返回融合后的嵌入和注意力权重
        # 注意力权重可以用于分析每个元路径的贡献
        return output, alphas

3、HeteGAT_no_coef

python 复制代码
class HeteGAT_no_coef(BaseGAttN):
    """
    HeteGAT_no_coef - 不返回注意力系数的版本

    这是HeteGAT的简化版本,不返回节点级别的注意力系数。
    适用于只需要最终分类结果,不需要分析注意力分布的场景。
    """

    def inference(inputs, nb_classes, nb_nodes, training, attn_drop, ffd_drop,
                  bias_mat_list, hid_units, n_heads, activation=tf1.nn.elu, residual=False,
                  mp_att_size=128):
        """
        前向传播(不返回注意力系数)

        参数与HeteGAT_multi相同
        """
        embed_list = []
        for bias_mat in bias_mat_list:
            attns = []
            head_coef_list = []
            for _ in range(n_heads[0]):
                # 不返回注意力系数
                attns.append(layers.attn_head(inputs, bias_mat=bias_mat,
                                                  out_sz=hid_units[0], activation=activation,
                                                  in_drop=ffd_drop, coef_drop=attn_drop, residual=False,
                                                  return_coef=False))
            h_1 = tf1.concat(attns, axis=-1)
            for i in range(1, len(hid_units)):
                h_old = h_1
                attns = []
                for _ in range(n_heads[i]):
                    attns.append(layers.attn_head(h_1,
                                                  bias_mat=bias_mat,
                                                  out_sz=hid_units[i],
                                                  activation=activation,
                                                  in_drop=ffd_drop,
                                                  coef_drop=attn_drop,
                                                  residual=residual))
                h_1 = tf1.concat(attns, axis=-1)
            embed_list.append(tf1.expand_dims(tf1.squeeze(h_1), axis=1))

        # 元路径级别的注意力融合
        multi_embed = tf1.concat(embed_list, axis=1)
        final_embed, att_val = layers.SimpleAttLayer(multi_embed, mp_att_size,
                                                     time_major=False,
                                                     return_alphas=True)
        # 输出层
        out = []
        for i in range(n_heads[-1]):
            out.append(tf1.layers.dense(final_embed, nb_classes, activation=None))

        logits = tf1.add_n(out) / n_heads[-1]
        print('de')
        logits = tf1.expand_dims(logits, axis=0)

        return logits, final_embed, att_val

4、HeteGAT

python 复制代码
class HeteGAT(BaseGAttN):
    """
    HeteGAT - 完整版本,支持返回注意力系数

    这是最完整的HAN实现,除了返回分类结果外,
    还可以返回节点级别的注意力系数,用于可解释性分析。

    返回的coef_list存储了每个元路径的节点注意力分布,
    可以帮助理解模型是如何关注不同邻居节点的。
    """

    def inference(inputs, nb_classes, nb_nodes, training, attn_drop, ffd_drop,
                  bias_mat_list, hid_units, n_heads, activation=tf1.nn.elu, residual=False,
                  mp_att_size=128,
                  return_coef=False):
        """
        前向传播(可选择返回注意力系数)

        参数:
            return_coef: 是否返回节点级别的注意力系数

        返回:
            logits: 分类logits
            final_embed: 最终嵌入
            att_val: 元路径注意力权重
            coef_list: 节点注意力系数列表 (可选)
        """
        embed_list = []
        coef_list = []  # 存储每个元路径的注意力系数

        for bias_mat in bias_mat_list:
            attns = []
            head_coef_list = []

            # 第一层:多头注意力
            for _ in range(n_heads[0]):
                if return_coef:
                    # 同时返回注意力系数和聚合后的特征
                    a1, a2 = layers.attn_head(inputs, bias_mat=bias_mat,
                                              out_sz=hid_units[0], activation=activation,
                                              in_drop=ffd_drop, coef_drop=attn_drop, residual=False,
                                              return_coef=return_coef)
                    attns.append(a1)
                    head_coef_list.append(a2)
                else:
                    attns.append(layers.attn_head(inputs, bias_mat=bias_mat,
                                                  out_sz=hid_units[0], activation=activation,
                                                  in_drop=ffd_drop, coef_drop=attn_drop, residual=False,
                                                  return_coef=return_coef))

            # 对多头的注意力系数取平均
            head_coef = tf1.concat(head_coef_list, axis=0)
            head_coef = tf1.reduce_mean(head_coef, axis=0)
            coef_list.append(head_coef)

            h_1 = tf1.concat(attns, axis=-1)

            # 后续隐藏层
            for i in range(1, len(hid_units)):
                h_old = h_1
                attns = []
                for _ in range(n_heads[i]):
                    attns.append(layers.attn_head(h_1,
                                                  bias_mat=bias_mat,
                                                  out_sz=hid_units[i],
                                                  activation=activation,
                                                  in_drop=ffd_drop,
                                                  coef_drop=attn_drop,
                                                  residual=residual))
                h_1 = tf1.concat(attns, axis=-1)

            embed_list.append(tf1.expand_dims(tf1.squeeze(h_1), axis=1))

        # 语义级注意力融合
        multi_embed = tf1.concat(embed_list, axis=1)
        final_embed, att_val = layers.SimpleAttLayer(multi_embed, mp_att_size,
                                                     time_major=False,
                                                     return_alphas=True)

        # 输出层
        out = []
        for i in range(n_heads[-1]):
            out.append(tf1.layers.dense(final_embed, nb_classes, activation=None))

        logits = tf1.add_n(out) / n_heads[-1]
        logits = tf1.expand_dims(logits, axis=0)

        if return_coef:
            return logits, final_embed, att_val, coef_list
        else:
            return logits, final_embed, att_val

tensorflow的核心部分讲完了,下面会讲解torch版本

相关推荐
QBoson2 小时前
基于多任务变分自编码器的晶格超材料力学性能逆向设计方法
人工智能·深度学习
xx_xxxxx_2 小时前
常见多模态架构CLIP/BLIP/Llava/CogVLM
人工智能·深度学习·机器学习·transformer·多模态
放下华子我只抽RuiKe53 小时前
深度学习-03-NLP强化训练
人工智能·深度学习·自然语言处理·开源·集成学习·easyui
sin°θ_陈3 小时前
前馈式3D Gaussian Splatting 研究地图(路线二):几何优先的前馈式 3DGS——前馈式 3DGS 如何重新拥抱多视图几何
深度学习·3d·webgl·三维重建·空间计算·3dgs·空间智能
剑穗挂着新流苏3123 小时前
204_从回归到分类:Softmax 回归、损失函数与多分类实战
人工智能·pytorch·python·深度学习
2501_9269783312 小时前
“LLM的智能本质--AGI的可能路径--人类的意识本质”三者的统一基底(5.0理论解读)
人工智能·经验分享·笔记·深度学习·机器学习·ai写作·agi
剑穗挂着新流苏31216 小时前
203_深度学习的第一步:线性回归模型与 SGD 优化算法实战
人工智能·深度学习·机器学习
是枚小菜鸡儿吖16 小时前
卷不动了?带你拆解 2026 深度学习核心版图:CNN、Transformer 与扩散模型的实战进化
深度学习·cnn·transformer
靴子学长16 小时前
Decoder only 架构下 - KV cache 的理解
pytorch·深度学习·算法·大模型·kv