矩阵求逆 (3,3) python - 硬编码与 numpy.linalg.inv

2024-05-03

对于大量矩阵,我需要计算定义为的距离度量:

尽管我确实知道强烈建议不要使用矩阵求逆,但我没有找到解决方法。因此,我尝试通过对矩阵求逆进行硬编码来提高性能,因为所有矩阵的大小均为 (3,3)。

我预计这至少会是一个微小的改进,但事实并非如此。

为什么 numpy.linalg.inv 比这种硬编码矩阵求逆更快/性能更高?

此外,我有什么替代方案来改善这个瓶颈?

def inversion(m):    
    m1, m2, m3, m4, m5, m6, m7, m8, m9 = m.flatten()
    determinant = m1*m5*m9 + m4*m8*m3 + m7*m2*m6 - m1*m6*m8 - m3*m5*m7 - m2*m4*m9  
    return np.array([[m5*m9-m6*m8, m3*m8-m2*m9, m2*m6-m3*m5],
                     [m6*m7-m4*m9, m1*m9-m3*m7, m3*m4-m1*m6],
                     [m4*m8-m5*m7, m2*m7-m1*m8, m1*m5-m2*m4]])/determinant

与随机 3*3 矩阵进行时序比较:

%timeit np.linalg.inv(a)

100000 个循环,3 次最佳:每个循环 12.5 µs

%timeit inversion(a)

100000 个循环,3 次最佳:每个循环 13.9 µs

密切相关但完全不重复的是这个post https://codereview.stackexchange.com/questions/154926/efficient-extraction-of-patch-features-over-an-image关于代码审查,解释了背景和整个功能。

EDIT:正如 @Divakar 在评论中建议的那样,m.ravel() 而不是 m.flatten() 稍微改进了反转,因此时序比较现在产生:

numpy - 100000 个循环,3 个循环中最好的:每个循环 12.6 µs

硬编码 - 100000 个循环,3 次最佳:每个循环 12.8 µs

尽管差距正在缩小,但硬编码的速度仍然较慢。为何如此?


这是一个简单的优化,节省了 9 次乘法和 3 次减法

def inversion(m):    
    m1, m2, m3, m4, m5, m6, m7, m8, m9 = m.ravel()
    inv = np.array([[m5*m9-m6*m8, m3*m8-m2*m9, m2*m6-m3*m5],
                    [m6*m7-m4*m9, m1*m9-m3*m7, m3*m4-m1*m6],
                    [m4*m8-m5*m7, m2*m7-m1*m8, m1*m5-m2*m4]])
    return inv / np.dot(inv[0], m[:, 0])

你可以通过一次性完成整个跟踪来挤出更多的操作(如果我数正确的话,还有 24 次乘法):

def det(m):
   m1, m2, m3, m4, m5, m6, m7, m8, m9 = m.ravel()
   return np.dot(m[:, 0], [m5*m9-m6*m8, m3*m8-m2*m9, m2*m6-m3*m5])
   # or try m1*(m5*m9-m6*m8) + m4*(m3*m8-m2*m9) + m7*(m2*m6-m3*m5)
   # probably the fastest would be to inline the two calls to det
   # I'm not doing it here because of readability but you should try it

def dist(m, n):
   m1, m2, m3, m4, m5, m6, m7, m8, m9 = m.ravel()
   n1, n2, n3, n4, n5, n6, n7, n8, n9 = n.ravel()
   return 0.5 * np.dot(
       m.ravel()/det(m) + n.ravel()/det(n),
       [m5*n9-m6*n8, m6*n7-m4*n9, m4*n8-m5*n7, n3*m8-n2*m9, n1*m9-n3*m7,
        n2*m7-n1*m8, m2*n6-m3*n5, m3*n4-m1*n6, m1*n5-m2*n4])

好的,这是内联版本:

import numpy as np
from timeit import timeit

def dist(m, n):
   m1, m2, m3, m4, m5, m6, m7, m8, m9 = m.ravel()
   n1, n2, n3, n4, n5, n6, n7, n8, n9 = n.ravel()
   return 0.5 * np.dot(
       m.ravel()/(m1*(m5*m9-m6*m8) + m4*(m3*m8-m2*m9) + m7*(m2*m6-m3*m5))
       + n.ravel()/(n1*(n5*n9-n6*n8) + n4*(n3*n8-n2*n9) + n7*(n2*n6-n3*n5)),
       [m5*n9-m6*n8, m6*n7-m4*n9, m4*n8-m5*n7, n3*m8-n2*m9, n1*m9-n3*m7,
        n2*m7-n1*m8, m2*n6-m3*n5, m3*n4-m1*n6, m1*n5-m2*n4])

def dist_np(m, n):
    return 0.5 * np.diag(np.linalg.inv(m)@n + np.linalg.inv(n)@m).sum()

for i in range(3):
    A, B = np.random.random((2,3,3))
    print(dist(A, B), dist_np(A, B))
    print('pp     ', timeit('f(A,B)', number=10000, globals={'f':dist, 'A':A, 'B':B}))
    print('numpy  ', timeit('f(A,B)', number=10000, globals={'f':dist_np, 'A':A, 'B':B}))

prints:

2.20109953156 2.20109953156
pp      0.13215381593909115
numpy   0.4334693900309503
7.50799877993 7.50799877993
pp      0.13934064202476293
numpy   0.32861811900511384
-0.780284449609 -0.780284449609
pp      0.1258618349675089
numpy   0.3110764700686559

请注意,您可以通过使用该函数的矢量化版本进行批处理来节省大量资金。该测试计算两批 100 个矩阵之间的所有 10,000 个成对距离:

def dist(m, n):
    m = np.moveaxis(np.reshape(m, m.shape[:-2] + (-1,)), -1, 0)
    n = np.moveaxis(np.reshape(n, n.shape[:-2] + (-1,)), -1, 0)
    m1, m2, m3, m4, m5, m6, m7, m8, m9 = m
    n1, n2, n3, n4, n5, n6, n7, n8, n9 = n
    return 0.5 * np.einsum("i...,i...->...",
        m/(m1*(m5*m9-m6*m8) + m4*(m3*m8-m2*m9) + m7*(m2*m6-m3*m5))
        + n/(n1*(n5*n9-n6*n8) + n4*(n3*n8-n2*n9) + n7*(n2*n6-n3*n5)),
        [m5*n9-m6*n8, m6*n7-m4*n9, m4*n8-m5*n7, n3*m8-n2*m9, n1*m9-n3*m7,
         n2*m7-n1*m8, m2*n6-m3*n5, m3*n4-m1*n6, m1*n5-m2*n4])

def dist_np(m, n):
    return 0.5 * (np.linalg.inv(m)@n + np.linalg.inv(n)@m)[..., np.arange(3), np.arange(3)].sum(axis=-1)

for i in range(3):
    A = np.random.random((100,1,3,3))
    B = np.random.random((1,100,3,3))
    print(np.allclose(dist(A, B), dist_np(A, B)))
    print('pp     ', timeit('f(A,B)', number=100, globals={'f':dist, 'A':A, 'B':B}))
    print('numpy  ', timeit('f(A,B)', number=100, globals={'f':dist_np, 'A':A, 'B':B}))

prints:

True
pp      0.14652886800467968
numpy   1.5294789629988372
True
pp      0.1482033939100802
numpy   1.6455406049499288
True
pp      0.1279512889450416
numpy   1.370200254023075
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

矩阵求逆 (3,3) python - 硬编码与 numpy.linalg.inv 的相关文章

随机推荐

  • 无法在 JDBCPreparedStatement 中使用 LIKE 查询吗?

    查询代码及查询方式 ps conn prepareStatement select instance id from eam measurement where resource id in select RESOURCE ID from
  • 解释为什么没有船的空 scenekit 场景只有一个节点和 2.73K 多边形

    为什么移除船舶后的空 scenekit 场景只有一个节点和 2 73K 多边形数 如果我展开统计视图 会看到两个节点和 5 46K 个多边形 它必须与统计视图有关 但为什么有这么多多边形 为什么这个视图会出现在场景内部 一个空的 Scene
  • 如何在特定时间启动Tornado周期性回调?

    目前在我的 Tornado 应用程序中 我正在使用定期调用回调PeriodicCallback每隔一小时 像这样 import tornado ioloop from tornado ioloop import PeriodicCallba
  • 将视图控制器推送到 UINavigationController 中

    我有一个带有导航控制器的选项卡视图控制器 在第一个选项卡项中 我单击视图中的按钮 弹出一个带有动画的视图 是 然后 当该视图完成后 我点击另一个按钮将其关闭 喜欢 self dismissViewControllerAnimated NO
  • tikz:为节点设置适当的x值

    这个问题源于这个问题here https stackoverflow com questions 2772972 latex curly braces outside math 我想生成一个跨越一些文本行的大括号 问题是我必须手动对齐 x
  • 如何将 typedef 结构传递给函数?

    此刻我正在努力 void avg everything 但这给了我错误 error subscripted value is neither array nor pointer 当我今天早些时候收到此错误时 这是 因为我没有正确地将 2D
  • 使用 PuLP 进行线性优化,变量附加条件

    我必须用 Pull 解决 Python 中的整数线性优化问题 我解决了基本问题 现在我必须添加额外的约束 有人可以帮助我用逻辑指示器添加条件吗 逻辑限制是 如果 A gt 20 则 B gt 5 这是我的代码 from pulp impor
  • 用于从多个目录复制和重命名文件的批处理文件

    我之前曾寻找过我的问题的答案 但到目前为止还没有具体的答案 看 使用xcopy将多个目录中的文件复制到一个目录 https stackoverflow com questions 585091 using xcopy to copy fil
  • OpenMP 动态调度与引导调度

    我正在研究 OpenMP 的调度 特别是不同的类型 我了解每种类型的一般行为 但澄清一下何时进行选择会很有帮助dynamic and guided调度 英特尔的文档 https software intel com en us articl
  • 如何将多个矩形打包为 2d 盒子俄罗斯方块样式

    我有许多不同宽度和高度的矩形 我有一个更大的矩形平台来放置它们 我想将它们包装在平台的一侧 以便它们在纵向 X 尺寸上展开 但将横向 Y 尺寸保持在最小限度 就是把它们像俄罗斯方块游戏一样放置 不能有重叠 但可以有间隙 有没有算法可以做到这
  • C++ 头文件包含

    我正在开发一个项目 每个头文件都有一个预处理器包含防护 我的包含是这样的 文件 gt 包含 main cpp gt header h 字符 h header h gt 矢量 iostream DataFiles h Character h
  • Dojo 是否可以与其他 JS 框架结合?

    我们使用 Dojo 1 9 3 作为构建单页面应用程序的 JS 框架 然而 我们在 Dojo 的怪癖上花费了太多时间 因此即使是简单的任务也需要很长时间才能实现 由于缺乏适当的文档 我们经常不得不求助于阅读源代码 然后实施解决方法 我觉得如
  • 在 Monogame 和 UIKit 之间切换

    我一直在搜索和搜索 但似乎找不到适合我想做的事情的解决方案 而且我几乎已经到了不得不问它是否可能的地步 我正在使用 Xamarin Studio 开发 iOS 应用程序 我有几个不同的屏幕设置为 UIViewController 它们运行良
  • Python中如何实现相对导入

    考虑 stuff init py mylib py Foo init py main py foo init py script py script py想要进口mylib py 这只是一个示例 但实际上我只想在父目录中进行模块的相对导入
  • git推送失败:`拒绝更新签出的分支:refs/heads/master`

    我想将我对 JBoss 配置的本地修改存储在 git 中 为此 我设置了以下结构 lrwxrwxrwx 1 jboss jboss 19 Jan 24 11 53 current gt jboss as 7 1 0 CR1b drwxr x
  • Spring:在属性文件中定义@RequestMapping值

    是否可以定义a的值 RequestMapping在 Spring 中通过在属性文件中定义注释 实际上 我做了类似的事情 Controller RequestMapping xxx public class MyController 但我想存
  • GridView,在代码中添加标题行第 2 部分

    这是这篇文章的延续 但添加了完整的代码 ASP NET GridView 在代码中添加标题行 https stackoverflow com questions 19119004 asp net gridview adding header
  • 对 MFC UI 应用程序进行单元测试吗?

    如何对大型 MFC UI 应用程序进行单元测试 我们有一些大型 MFC 应用程序已经开发了很多年 我们使用一些标准的自动化 QA 工具来运行基本脚本来检查基础知识 文件打开等 这些由 QA 小组在日常构建后运行 但我们希望引入一些程序 以便
  • Web 服务无法使用 GAC 中的类型创建类型错误

    遇到一个不寻常的问题时 我似乎喜欢做一些不常见的事情 我有一个复合控件 它检查给定的 Web 服务文件是否存在于我的应用程序的根目录中 如果不存在 它会在标记中创建带有必要指令的文件以进行滚动 如下所示 反过来 它被保存到输出中 完成此步骤
  • 矩阵求逆 (3,3) python - 硬编码与 numpy.linalg.inv

    对于大量矩阵 我需要计算定义为的距离度量 尽管我确实知道强烈建议不要使用矩阵求逆 但我没有找到解决方法 因此 我尝试通过对矩阵求逆进行硬编码来提高性能 因为所有矩阵的大小均为 3 3 我预计这至少会是一个微小的改进 但事实并非如此 为什么