技术背景

坐标变换、旋转矩阵,是在线性空间常用的操作,在分子动力学模拟领域有非常广泛的应用。比如在一个体系中切换坐标,或者对整体分子进行旋转平移等。如果直接使用Numpy,是很容易可以实现的,只要把相关的旋转矩阵写成numpy.array的形式即可。但是在一些使用GPU计算的深度学习框架中,比如MindSpore框架,则是不能直接支持这样操作的。因此我们需要探索一下如何在MindSpore框架中实现一个简单的旋转矩阵,并使用旋转矩阵进行一些旋转操作。

Jax.numpy旋转矩阵

我们先介绍一下在常用的Numpy库中是如何实现一个旋转矩阵的,这里为了演示方便,简化编程工作量,我们选择用Jax中所集成的Numpy来进行试验和对比。这里我们计算的场景是,给定一个N原子的分子体系,其空间维度为D=3,我们通过给定三个欧拉角,来旋转整个分子系统。这就需要我们分别定义三个维度的旋转矩阵\(R_x(\phi),R_y(\psi),R_z(\theta)\),分别表示绕\(X\)轴旋转\(\phi\)的角度、绕\(Y\)轴旋转\(\psi\)的角度,以及绕\(Z\)轴旋转\(\theta\)的角度。如果使用Jax来进行编程,那我们得到的旋转矩阵应该是如下的形式:

def rotation(psi,phi,theta,v):
""" Module of rotation in 3 Euler angles. """
RY = np.array([[np.cos(psi),0,-np.sin(psi)],
[0, 1, 0],
[np.sin(psi),0,np.cos(psi)]])
RX = np.array([[1,0,0],
[0,np.cos(phi),-np.sin(phi)],
[0,np.sin(phi),np.cos(phi)]])
RZ = np.array([[np.cos(theta),-np.sin(theta),0],
[np.sin(theta),np.cos(theta),0],
[0,0,1]])
return np.dot(RZ,np.dot(RX,np.dot(RY,v))) multi_rotation = jit(vmap(rotation,(None,None,None,0)))

接下来使用这个旋转矩阵来展示一个具体的案例:

In [1]: from jax import numpy as np
In [2]: from jax import jit, vmap In [3]: def rotation(psi,phi,theta,v):
...: """ Module of rotation in 3 Euler angles. """
...: RY = np.array([[np.cos(psi),0,-np.sin(psi)],
...: [0, 1, 0],
...: [np.sin(psi),0,np.cos(psi)]])
...: RX = np.array([[1,0,0],
...: [0,np.cos(phi),-np.sin(phi)],
...: [0,np.sin(phi),np.cos(phi)]])
...: RZ = np.array([[np.cos(theta),-np.sin(theta),0],
...: [np.sin(theta),np.cos(theta),0],
...: [0,0,1]])
...: return np.dot(RZ,np.dot(RX,np.dot(RY,v)))
...: In [4]: multi_rotation = jit(vmap(rotation,(None,None,None,0))) In [5]: import numpy as onp In [6]: v=onp.random.random((3,3)) In [7]: v
Out[7]:
array([[0.97911664, 0.48098486, 0.44966794],
[0.25350689, 0.50949849, 0.77506796],
[0.24502845, 0.23313826, 0.72014647]]) In [8]: multi_rotation(onp.pi, onp.pi, 0, v)
Out[8]:
DeviceArray([[-0.97911656, -0.4809849 , 0.449668 ],
[-0.25350684, -0.50949854, 0.7750679 ],
[-0.24502839, -0.23313832, 0.7201465 ]], dtype=float32)

在这个案例中,我们给定了绕X和Y轴分别旋转180度的操作,而对Z轴则保持相对静止。可想而知我们所得到的结果会使得X和Y的值分别取负号,而Z的值保持不变,上述的测试结果也表明这个计算过程是正确的。

MindSpore旋转矩阵

在MindSpore深度学习框架中,有一点不同于Numpy和Jax的是,MindSpore的Tensor中的元素不能包含有object。在上一个章节的案例中其实我们可以发现,旋转矩阵的元素中包含了一些正弦余弦函数的使用。假如我们使用MindSpore去计算正余弦函数值的话,得到的输出结果会是一个Tensor,而不是一个常数。比较尴尬的是,MindSpore的Tensor只能使用常数来初始化,这里矛盾点就出现了。那么我们只有两个途径可以解决这个问题:将输入的角度转化成普通numpy的格式,使用cpu上的numpy计算完成旋转矩阵之后,在输出的时候再转化为MindSpore的Tensor。而另一操作就是,先把所有的旋转矩阵的元素计算好之后,将这些元素concat起来变成一个一维的Tensor,再对该Tensor做一个reshape,就可以得到我们想要的旋转矩阵所对应的Tensor。在如下的示例中我们使用的是第二种方案:

In [1]: from mindspore import ops, Tensor

In [2]: import mindspore as ms

In [3]: import numpy as np

In [4]: psi = Tensor([np.pi], ms.float32)

In [5]: phi = Tensor([np.pi], ms.float32)

In [6]: theta = Tensor([0.], ms.float32)

In [7]: v = Tensor(np.random.random((3,3)), ms.float32)

In [8]: v
Out[8]:
Tensor(shape=[3, 3], dtype=Float32, value=
[[ 4.51581478e-01, 7.52180338e-01, 2.84639597e-01],
[ 8.46439958e-01, 2.95659006e-01, 1.81022584e-01],
[ 8.94563913e-01, 2.25287616e-01, 1.71754003e-01]]) In [9]: zero = Tensor([0.], ms.float32) In [10]: one = Tensor([1.], ms.float32) In [11]: def rotation(psi, phi, theta, v):
...: RY = ops.Concat(-1)((ops.Cos()(psi), zero, -ops.Sin()(psi),
...: zero, one, zero,
...: ops.Sin()(psi), zero, ops.Cos()(psi)))
...: RY = RY.reshape(3, 3)
...: RX = ops.Concat(-1)((one, zero, zero,
...: zero, ops.Cos()(phi), -ops.Sin()(phi),
...: zero, ops.Sin()(phi), ops.Cos()(phi)))
...: RX = RX.reshape(3, 3)
...: RZ = ops.Concat(-1)((ops.Cos()(theta), -ops.Sin()(theta), zero,
...: ops.Sin()(theta), ops.Cos()(theta), zero,
...: zero, zero, one))
...: RZ = RZ.reshape(3, 3)
...: dot = ops.Einsum('ij,kj->ki')
...: return dot((RZ, dot((RX, dot((RY, v))))))
...: In [12]: rotation(psi, phi, theta, v)
Out[12]:
Tensor(shape=[3, 3], dtype=Float32, value=
[[-4.51581448e-01, -7.52180338e-01, 2.84639567e-01],
[-8.46439958e-01, -2.95659035e-01, 1.81022629e-01],
[-8.94563913e-01, -2.25287631e-01, 1.71754062e-01]])

从这个计算结果中,我们可以看到跟Jax的案例一样,也是得到了X和Y值分别取负数的结果,程序是正确运行的。但是这里关于案例代码,需要一些额外的解释:

  1. 在上述案例中,我们先定义了一系列的一维Tensor来作为旋转矩阵的元素,使用MindSpore的Concat算子将这些一维Tensor的最后一维取出组成一个新的Tensor,再对其做reshape操作,得到一个我们所需要的旋转矩阵。
  2. 在Jax中我们是使用了vmap将旋转矩阵对单个矢量旋转的操作扩展到对多个矢量的旋转操作,而在MindSpore中虽然也支持了Vmap的算子,但是这里我们使用的是MindSpore所支持的另外一个功能:爱因斯坦求和算子。使用这个算子,我们就允许了旋转矩阵直接对多个矢量输入的指定维度进行运算,一样也可以得到我们想要的计算结果。

总结概要

本文介绍了两个不同的深度学习框架:Jax和MindSpore下的旋转矩阵的实现,对于不同的框架来说同一个功能会涉及到不同的实现方式。在Jax中,由于其函数式编程的特性,就允许我们更加简单的去构造和扩展一个旋转矩阵。MindSpore是一个面向对象编程的框架,其优势在于构建大型的模型应用。但构造一个可用的简单模型,相对而言就会走一些弯路。就比如我们需要使用Concat+Reshape的算子来拼接一个旋转矩阵,看起来会相对麻烦一些。而构建好旋转矩阵之后,则可以使用跟Jax一样的Vmap操作,或者是直接使用爱因斯坦求和来计算旋转矩阵对多个矢量输入的计算,从文章中的案例中可以看到两者所得到的计算结果是一致的。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/mindrot.html

作者ID:DechinPhy

更多原著文章请参考:https://www.cnblogs.com/dechinphy/

打赏专用链接:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

腾讯云专栏同步:https://cloud.tencent.com/developer/column/91958

CSDN同步链接:https://blog.csdn.net/baidu_37157624?spm=1008.2028.3001.5343

51CTO同步链接:https://blog.51cto.com/u_15561675

使用MindSpore计算旋转矩阵的更多相关文章

  1. c++ 知道旋转前后矩阵向量值 求旋转矩阵c++/c#代码 知道两个向量求他们的旋转矩阵

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12115244.html 知道旋转前后矩阵向量值 如何去求旋转矩阵R 的c++/c#代码??? ...

  2. 使用四元数解决万向节锁(Gimbal Lock)问题

    问题 使用四元数可以解决万向节锁的问题,但是我在实际使用中出现问题:我设计了一个程序,显示一个三维物体,用户可以输入绕zyx三个轴进行旋转的指令,物体进行相应的转动. 由于用户输入的是绕三个轴旋转的角 ...

  3. ICP算法(Iterative Closest Point迭代最近点算法)

    标签: 图像匹配ICP算法机器视觉 2015-12-01 21:09 2217人阅读 评论(0) 收藏 举报 分类: Computer Vision(27) 版权声明:本文为博主原创文章,未经博主允许 ...

  4. UVa OJ 197 - Cube (立方体)

    Time limit: 30.000 seconds限时30.000秒 Problem问题 There was once a 3 by 3 by 3 cube built of 27 smaller ...

  5. 【转】 CATransform3D 矩阵变换之立方体旋转实现细节

    原文网址:http://blog.csdn.net/ch_soft/article/details/7351896 第一部分.前几天做动画,使用到了CATransform3D ,由于没有学过计算机图形 ...

  6. OpenGL: Rotation vector sensor of Android and Device motion of iOS

    为了实现一个全景图片展示的功能,需要借助手机的姿态传感器,实现一个这样的功能:当手机旋转时,视角也跟着旋转(读者若理解不能,可以参考下现在流行的 VR 应用,使用陀螺仪模式时的效果,亦可称作" ...

  7. 《图像处理实例》 之 目标旋转矫正(基于区域提取、DFT变换)

    目标:1.把矩形旋转正.          2.把文字旋转校正.                                                                     ...

  8. 迭代最近点算法 Iterative Closest Points

    研究生课程系列文章参见索引<在信科的那些课> 基本原理 假定已给两个数据集P.Q, ,给出两个点集的空间变换f使他们能进行空间匹配.这里的问题是,f为一未知函数,而且两点集中的点数不一定相 ...

  9. c++ MFC图像处理CImage类常用操作代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html MFC图像处理CImage类常用操作 CImage类头文件为#inclu ...

随机推荐

  1. 【Spring】AOP实现原理(二):Advisor获取

    @EnableAspectJAutoProxy @EnableAspectJAutoProxy注解可以用来开启AOP,那么就从@EnableAspectJAutoProxy入手学习一下Spring A ...

  2. JAVA设计模式总结—建造者模式

    建造者模式 模式动机与定义 ​ 首先建造者模式的动机是为了创建复杂对象,简化传统的创建方法,提高创建的效率和可读性. ​ 像图中的这个例子,用户的需求是驾驶一辆汽车,但是对于用户来说是不需要了解汽车装 ...

  3. windows server2012R2 上 .net core IIS 部署--应用程序池 自动停止

    在windows server2016安装部署.NET CORE时,只需要将.net core应用程序池设置无托管,然后对应你项目的版本安装一个dotnet-hosting-2.2.6-win.exe ...

  4. 多校联训 DP 专题

    [UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...

  5. docker快速安装openvas

    项目地址 1.更换国内docker源 2.docker run -d -p 443:443 -e PUBLIC_HOSTNAME=此处填你宿主机IP --name openvas mikesplain ...

  6. (一)java基础篇---第一个程序

    先认识java的基础知识 1.变量命名规则 :1)变量名由数字字母下划线组成,2)不能使用java的关键字,比如public这种,3)遵循小驼峰命名法 2.数据类型 2.1基本数据类型有8种 其中分为 ...

  7. CF1703B ICPC Balloons 题解

    题意:输入每个团队及团队的解决问题数,若是第一次解决则获得两个气球,其余获得一个气球. 做法:开一个数组记录是否为第一次解决该问题,直接模拟. #include<cstdio> #incl ...

  8. 没错,请求DNS服务器还可以使用UDP协议

    目录 简介 搭建netty客户端 在netty中发送DNS查询请求 DNS消息的处理 总结 简介 之前我们讲到了如何在netty中构建client向DNS服务器进行域名解析请求.使用的是最常见的TCP ...

  9. python opencv图像识别(相同大小图片)

    简介 由于项目需要对比两张相同图片的相似度,因此采用opencv将图片转为灰阶数组,然后对比相应的数组来取相似度,此方法只适用于大小相同的图片,较为局限 # -*- coding: utf-8 -*- ...

  10. 技术分享 | ARM下中标麒麟系统ky10使用Xtrabackup-8.0.25

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 一.需求背景 查询Percona官方手册,Xtrabackup 8.0可以备份M ...