【代码解读】LLGC

news2024/9/21 21:34:47

对象创建:

model = LLGC(description.size(1), label.max().item()+1, args.drop_out, args.use_bias).to(device)

模型使用:

output = model(train_features)

LLGC:

# Lorentzian MODEL
class LLGC(nn.Module):
    def __init__(self, nfeat, nclass, drop_out, use_bias):
        super(LLGC, self).__init__()
        self.drop_out = drop_out
        self.use_bias = use_bias
        self.nclass = nclass
        
        self.c = torch.tensor([1.0]).to("cuda")
        
        self.manifold = getattr(manifolds_LLGC, "Lorentzian")()
        
        #创建了manifolds中的一个lorentzian类的对象,赋值给self.manifold
        self.W = LorentzLinear(self.manifold, nfeat, nclass, self.c, self.drop_out, self.use_bias)

    def forward(self, x, batch_size):
    
        x_loren = self.manifold.normalize_input(x, self.c)
        #normalize_input操作内部带有对数映射,self.c为曲率。x_loren为对数映射后的结果
        x_w = self.W(x_loren)
        
        x_tan = self.manifold.log_map_zero(x_w, self.c)
        
        return x_tan[:batch_size]
  1. 欧式空间中的点到流形的映射
  2. 计算
  3. 流形映射到欧式空间

1. 欧式空间中的点到流形的映射

目标是使用self.manifold.normalize_input将欧式空间的目标特征x映射到流形上,返回x_loren

x_loren = self.manifold.normalize_input(x, self.c)

创建一个全零张量。
将全零张量和输入张量拼接,增加一个额外的维度。
调用exp_map_zero

    def normalize_input(self, x, c):
        # print('=====normalize original input===========')
        num_nodes = x.size(0)
        zeros = torch.zeros(num_nodes, 1, dtype=x.dtype, device=x.device)
        x_tan = torch.cat((zeros, x), dim=1)
        return self.exp_map_zero(x_tan, c)

创建流形上的基点

    def exp_map_zero(self, dp, c, is_res_normalize=True, is_dp_normalize=True):
        zeros = torch.zeros_like(dp)
        zeros[:, 0] = c ** 0.5
        return self.exp_map_x(zeros, dp, c, is_res_normalize, is_dp_normalize)

exp_map_x 方法通过指数映射将一个点 p 和切向量 dp 映射回洛伦兹流形上。
首先规范化切向量 dp。
然后计算其洛伦兹范数。
接着通过指数映射公式将其映射到流形上,并可选地对结果进行规范化。

    def exp_map_x(self, p, dp, c, is_res_normalize=True, is_dp_normalize=True):
        if is_dp_normalize:
            dp = self.normalize_tangent(p, dp, c)
        dp_lnorm = self.l_inner(dp, dp, keep_dim=True)
        dp_lnorm = torch.sqrt(torch.clamp(dp_lnorm + self.eps[p.dtype], 1e-6))
        dp_lnorm_cut = torch.clamp(dp_lnorm, max=50)
        sqrt_c = c ** 0.5
        res = (torch.cosh(dp_lnorm_cut / sqrt_c) * p) + sqrt_c * (torch.sinh(dp_lnorm_cut / sqrt_c) * dp / dp_lnorm)
        if is_res_normalize:
            res = self.normalize(res, c)
        return res

normalize_tangent 方法的目的是规范化洛伦兹流形上切向量,使其满足洛伦兹内积 <p, p_tan>_L = 0

    def normalize_tangent(self, p, p_tan, c):
        """
        Normalize tangent vectors to place the vectors satisfies <p, p_tan>_L=0
        :param p: the tangent spaces at p. size:[nodes, feature]
        :param p_tan: the tangent vector in tangent space at p
        """
        d = p_tan.size(1) - 1
        p_tail = p.narrow(1, 1, d)
        p_tan_tail = p_tan.narrow(1, 1, d)
        ptpt = torch.sum(p_tail * p_tan_tail, dim=1, keepdim=True)
        p_head = torch.sqrt(c + torch.sum(torch.pow(p_tail, 2), dim=1, keepdim=True) + self.eps[p.dtype])
        return torch.cat((ptpt / p_head, p_tan_tail), dim=1)

计算内积

    def l_inner(self, x, y, keep_dim=False):
        # input shape [node, features]
        d = x.size(-1) - 1
        xy = x * y
        xy = torch.cat((-xy.narrow(1, 0, 1), xy.narrow(1, 1, d)), dim=1)
        return torch.sum(xy, dim=1, keepdim=keep_dim)

目的是将一个向量 p 规范化,以确保它位于双曲面上。
这个过程可以理解为确保该向量符合双曲空间的几何结构。

    def normalize(self, p, c):
        """
        Normalize vector to confirm it is located on the hyperboloid
        :param p: [nodes, features(d + 1)]
        :param c: parameter of curvature
        """
        d = p.size(-1) - 1
        narrowed = p.narrow(-1, 1, d)
        if self.max_norm:
            narrowed = torch.renorm(narrowed.view(-1, d), 2, 0, self.max_norm)
        first = c + torch.sum(torch.pow(narrowed, 2), dim=-1, keepdim=True)
        first = torch.sqrt(first)
        return torch.cat((first, narrowed), dim=1)

2. 计算

x_w = self.W(x_loren)

其中LorentzLinear的类定义如下:

class LorentzLinear(nn.Module):
    # Lorentz Hyperbolic Graph Neural Layer
    def __init__(self, manifold, in_features, out_features, c, drop_out, use_bias):
        super(LorentzLinear, self).__init__()
        # print("LorentzLinear")
        self.manifold = manifold
        self.in_features = in_features
        self.out_features = out_features
        self.c = c
        self.drop_out = drop_out
        self.use_bias = use_bias
        
        self.bias = nn.Parameter(torch.Tensor(out_features-1))   # -1 when use mine mat-vec multiply
        self.weight = nn.Parameter(torch.Tensor(out_features - 1, in_features))  # -1, 0 when use mine mat-vec multiply
        
        self.reset_parameters()

    def reset_parameters(self):
        init.xavier_uniform_(self.weight, gain=math.sqrt(2))
        init.constant_(self.bias, 0)

    def forward(self, x):
        drop_weight = F.dropout(self.weight, self.drop_out, training=self.training)
        mv = self.manifold.matvec_regular(drop_weight, x, self.bias, self.c, self.use_bias)
        return mv

dropout的输入可以是特征,也可以是权值矩阵。
总归返回的是,以概率p随机给元素置零之后的输入。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


对输入执行对数映射。
分割映射结果。
矩阵乘法(将 x_tail 和权重矩阵 m 进行矩阵乘法。注意,这里对 m 执行了转置操作,以确保维度匹配)。
拼接结果,恢复到原有的维度。
首先执行 normalize_tangent_zero,将数据归一化到洛伦兹流形的切空间。再通过 执行指数映射,将数据映射回洛伦兹流形。
检查 mx 中的元素是否为零,用零替换掉 mx 中满足某个条件的部分。

    def matvec_regular(self, m, x, b, c, use_bias):
        d = x.size(1) - 1
        x_tan = self.log_map_zero(x, c)
        x_head = x_tan.narrow(1, 0, 1)
        x_tail = x_tan.narrow(1, 1, d)
        mx = x_tail @ m.transpose(-1, -2)
        if use_bias:
            mx_b = mx + b
        else:
            mx_b = mx
        mx = torch.cat((x_head, mx_b), dim=1)
        mx = self.normalize_tangent_zero(mx, c)
        mx = self.exp_map_zero(mx, c)
        cond = (mx==0).prod(-1, keepdim=True, dtype=torch.uint8)
        res = torch.zeros(1, dtype=mx.dtype, device=mx.device)
        res = torch.where(cond, res, mx)
        return res
    def log_map_zero(self, y, c, is_tan_normalize=True):
        zeros = torch.zeros_like(y)
        zeros[:, 0] = c ** 0.5

        return self.log_map_x(zeros, y, c, is_tan_normalize)

对数映射的作用是将洛伦兹流形上的点投影到某个点 x 的切空间中(即欧几里得空间)。
通过内积调整 y,得到一个新的向量 tmp_vector。
计算 tmp_vector 的范数。
计算切向量 y_tan。
如果 is_tan_normalize 为真,则对计算得到的切向量 y_tan 进行归一化处理,确保它满足洛伦兹切空间的约束。

    def log_map_x(self, x, y, c, is_tan_normalize=True):
        """
        Logarithmic map at x: project hyperboloid vectors to a tangent space at x
        :param x: vector on hyperboloid
        :param y: vector to project a tangent space at x
        :param normalize: whether normalize the y_tangent
        :return: y_tangent
        """
        xy_distance = self.induced_distance(x, y, c)
        tmp_vector = y + self.l_inner(x, y, keep_dim=True) / c * x
        tmp_norm = torch.sqrt(self.l_inner(tmp_vector, tmp_vector) + self.eps[x.dtype])
        y_tan = xy_distance.unsqueeze(-1) / tmp_norm.unsqueeze(-1) * tmp_vector
        if is_tan_normalize:
            y_tan = self.normalize_tangent(x, y_tan, c)
        return y_tan

这里通过 induced_distance 方法计算向量 x 和 y 在洛伦兹流形上的距离,这实际上是两点在洛伦兹空间的测地线距离。

    def induced_distance(self, x, y, c):
        xy_inner = self.l_inner(x, y)
        sqrt_c = c ** 0.5
        return sqrt_c * arcosh(-xy_inner / c + self.eps[x.dtype])

3. 流形映射到欧式空间

x_tan = self.manifold.log_map_zero(x_w, self.c)

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

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

相关文章

家政保洁|基于SSM+vue的智能家政保洁预约系统(源码+数据库+文档)

智能家政保洁预约系统 基于SSMvue的智能家政保洁预约系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 后台模块实现 管理员功能实现 家政人员功能实现 用户功能实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…

多维动态规划-面试高频!-最长公共子序列和最长公共子串、回文串-c++实现和详解

1143. 最长公共子序列 中等 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删…

UE驻网失败问题(三)

这个问题是lab问题&#xff0c;现象如下&#xff1a; 期望UE注册在SA网络下&#xff0c;咋一看没有5G MIB/SIB1打印&#xff0c;好像是没搜到5G小区&#xff0c;而实际上并不是这样。 在查看搜网过程时会发现如下log打印&#xff1a; [I nr5g_rrc_acq.c 3544] RRC ACQ: Band 41…

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

01 引言 随着时间的发展&#xff0c;大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用&#xff0c;随着人们期望的不断增加&#xff0c;目标也发生了巨大的变化。在短短的几个月的时间里&#xff0c;人们对大模型的认识已经从对其zero-shot能力感到惊讶&#xff0c…

ElasticSearch-Ingest Pipeline Painless Script

Ingest Node & Pipeline & Processor Ingest NodePipeline & Processor内置的 Processors创建 pipeline使用 pipeline 更新数据借助 update_by_query 更新已存在的文档Ingest Node VS Logstash Painless Ingest Node & Pipeline & Processor 应用场景&…

坚持与等待的区别!看了当年高考状元如今的现状,我才明白所谓名校的真相——早读(逆天打工人爬取热门微信文章解读)

快 机会来了 引言Python 代码第一篇 洞见 看了当年高考状元如今的现状&#xff0c;我才明白所谓名校的真相第二篇 股市 之 空窗期结尾 &#xff08;不是 你改名 怎么改群名字&#xff01; 这下每个人都知道王妈妈单身了&#xff09; 引言 昨天忘记写了 真的很抱歉 说下借口哈…

Invicti-Professional-V24.8.1

前言 Invicti 专业 Web 应用程序安全扫描器 自动、极其准确且易于使用的 Web 应用程序安全扫描程序&#xff0c;可自动查找网站、Web 应用程序和 Web 服务中的安全漏洞。 Invicti Professional Edition 是一款商业 Web 应用程序安全扫描器。它旨在自动查找和修复 Web 应用程…

VScode:快捷键和技巧

格式化文档 搜索文件名

助贷CRM系统:为金融中介行业打造全新营销管理模式

助贷CRM&#xff08;客户关系管理&#xff09;系统是针对金融中介行业&#xff0c;特别是从事贷款助贷业务的机构设计的一套综合管理系统。该系统旨在通过数字化、智能化的手段&#xff0c;优化金融中介机构的营销、销售、客户管理及服务流程&#xff0c;提升运营效率&#xff…

构建高效在线拍卖系统:SpringBoot实践

MySQL数据库 数据库是系统开发过程中不可或缺的一部分。 在WEB应用方面&#xff0c;MySQL AB开发了一个具有很大优势的MySQL关系数据库管理系统。 MySQL可以将数据存储在不同的表中&#xff0c;这非常灵活&#xff0c;并且还可以提高系统在实际应用中的速度。 数据库访问最常用…

创客匠人8月总结|所有赋能都是服务,都是为了帮客户拿结果

“九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。”每一份伟大的成就都源自不懈的积累与坚定的步伐。 作为“知识变现整体解决方案服务商”&#xff0c;我们始终站在时代的前沿&#xff0c;致力于为每一位知识IP搭建桥梁&#xff0c;直通知识变现之…

软件工程造价师习题练习 24

1.关于功能点方法&#xff0c;以下描述不正确的是( ) A. 可用于项目范围管理 B. 可用于澄清需求 C. 反映软件功能规模的大小 D. 与软件开发成本高度相关 功能点方法是一种用于软件规模估算的方法&#xff0c;它主要用于衡量软件的功能规模大小。功能点分析不直接与软件开发…

杀毒软件火绒下载地址

杀毒软件火绒下载地址

【深度学习实战】使用深度学习模型可视化工具——Netron在线可视化深度学习神经网络

一直以来&#xff0c;对于深度学习领域的开发者&#xff0c;可视化模型都是非常迫切的需求&#xff0c;今天主要介绍一款可视化工具——Netron Netron有三种使用方式&#xff1a;在线、本地安装、pip安装 今天在这里只介绍在线使用这种方式。 Netron有个官方的网站&#xff1…

SOC 阵列:创新算力的未来之路

一、SOC阵列的概念与发展历程 SOC 阵列是由多个特定功能集成电路组合在一个芯片上的系统或产品&#xff0c;包含硬件系统及嵌入式软件。从传统集成电路到 SOC 经历多个阶段&#xff0c;初期电路由分立元件组成&#xff0c;后集成到单芯片集成电路中&#xff0c;其发展遵循摩尔…

『功能项目』协程生成怪物模型【25】

打开上一篇24AssetBundle上传加载u3d模型的项目&#xff0c; 本章要做的事情是在项目运行14秒后生成一个怪物鲸鱼&#xff0c;并且怪物鲸鱼会根据路径点自动巡航 在资源商店免费下载怪物模型 重命名为MonsterWhale 创建一个空物体 重命名为Path 在子级下创建小球Sphere作为巡…

STM32CubeIMX修改库文件代码相关问题

有时候会遇到需要需要修改库文件的需求&#xff0c;比如下面两种情况&#xff1a; 1、库文件有问题 2、库文件需要修改以适配当前需求 修改库文件的目的是&#xff0c;当下次生成程序的时候直接生成修改后的&#xff0c;无需在修改库文件。 直接将修改替换至默认文件&#xff…

软件安全测试有多重要?第三方软件测试公司如何进行安全测试?

在当今信息化迅速发展的社会&#xff0c;软件的安全性越来越受到重视。近年来&#xff0c;我国的网络安全形势日趋复杂&#xff0c;各类网络攻击层出不穷&#xff0c;软件泄露、数据丢失等事件屡见不鲜。为了保障软件项目的安全性&#xff0c;安全测试必不可少。 软件安全测试…

物流计算面单物流单标签打印软件 佳易王物流管理系统下载操作教程

一、前言 物流计算面单物流单标签打印软件 佳易王物流管理系统下载操作教程 1、佳易王物流管理系统软件分两个版本&#xff0c;一个是大众版&#xff0c;一个是高级版&#xff0c;本例以大众版为例说明 软件在打印物流单的同时可以打印标签 2、软件为免安装版&#xff0c;解…

使用matplotlab绘制多条形图

##黑马程序学习 这种多个条形图放在一起的图形该怎么画呢&#xff1f; 请看以下代码 #横着的条形图 from matplotlib import pyplot as plt import matplotlib#设置显示中文 和 负号 matplotlib.rcParams[font.sans-serif][SimHei] matplotlib.rcParams[axes.unicode_minus]F…