首页 > 编程问答 >无法正确使用“comm.Gatherv()”来收集大小不均匀的 numpy 数组

无法正确使用“comm.Gatherv()”来收集大小不均匀的 numpy 数组

时间:2024-07-24 06:46:55浏览次数:9  
标签:python numpy mpi mpi4py

我正在学习 MPI4Py,我想实现一个简单的程序。

解释
这里,每个等级都有一个 send_array 大小 rank+1 和值分别等于 rank+1

rank0 = [1]
rank1 = [2 2]
rank2 = [3 3 3]
rank3 = [4 4 4 4]

我想收集值 rank=0 到缓冲区 rbuf 它的大小等于所有本地 send_arrays 的总大小,即 1+2+3+4 = 10

程序

from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

send_array = np.ones(rank+1).astype(int) * (rank + 1)

print(rank, send_array)
if rank == 0:
    gather_size = np.array([sum([i+1 for i in range(size)])])
    print(gather_size)

    rbuf = np.zeros(gather_size[0]).astype(int)
else:
    gather_size = None
    rbuf = None

# comm.Gatherv(sendbuf, recvbuf=(recvbuf, recvcounts, displs, datatype), root=0)
comm.Gatherv(sendbuf=send_array, recvbuf=(rbuf, (1,2,3,4),(0,1,3,6), MPI.INT), root=0)

 
if rank == 0:
    print(rbuf, len(rbuf))

观察/错误/怀疑

我手动将这些值硬编码为更明确,因为我有疑问关于 recvcounts displs 的值。我收到以下错误:

comm.Gatherv(sendbuf=send_array, recvbuf=(rbuf, (1,2,3,4),(0,1,3,6), MPI.INT), root=0)
  File "mpi4py/MPI/Comm.pyx", line 724, in mpi4py.MPI.Comm.Gatherv
mpi4py.MPI.Exception: MPI_ERR_TRUNCATE: message truncated

我期望的结果是:

[1 2 2 3 3 3 4 4 4 4]

玩了一下之后,我还意识到代码 有效 如果我保持 rbuf 的大小等于 [| ||],在本例中可能是 maximum_local_array_size*number_of_ranks ,因为我有 4 个等级。 4*4 我得到的结果不是我想要的,但我没有收到任何错误。请注意,这次我也没有指定

from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

# send_array = np.ones(10).astype(int) * (rank + 1)
send_array = np.ones(rank+1).astype(int) * (rank + 1)

print(rank, send_array)
if rank == 0:
    gather_size = np.array([16])
    print(gather_size)

    rbuf = np.zeros(gather_size[0]).astype(int)
else:
    gather_size = None
    rbuf = None

# comm.Gatherv(sendbuf, recvbuf=(recvbuf, recvcounts, displs, datatype), root=0)
comm.Gatherv(sendbuf=send_array, recvbuf=(rbuf, MPI.INT), root=0)
 
if rank == 0:
    print(rbuf, len(rbuf))

recvcounts 所以我不确定这些参数默认使用的确切值是什么,因为这些值似乎有效。 displs . So I am not sure what exact values are used by default for these arguments, since those seem to work.

[1 0 0 0 2 2 0 0 3 3 3 0 4 4 4 4]

你的 recvcounts displs 参数的理解是正确的。但是,你遇到的问题在于 Gatherv 操作如何将数据放入接收缓冲区( rbuf )。

在你的代码中,你正确地计算了 recvcounts (1, 2, 3, 4) displs (0, 1, 3, 6) 。这意味着:

  • 进程 0 发送 1 个元素,这些元素应该放在 rbuf 的索引 0 处开始。
  • 进程 1 发送 2 个元素,这些元素应该放在 rbuf 的索引 1 处开始。
  • 进程 2 发送 3 个元素,这些元素应该放在 rbuf 的索引 3 处开始。
  • 进程 3 发送 4 个元素,这些元素应该放在 rbuf 的索引 6 处开始。

问题在于,当你使用 recvcounts displs 时, Gatherv 不会 将接收到的数据视为一个连续的数组。相反,它将接收到的数据视为多个块,每个块都由 recvcounts displs 指定。

因此,当你在进程 0 上打印 rbuf 时,你会看到:

[1 0 0 0 2 2 0 0 3 3 3 0 4 4 4 4]

这是因为 Gatherv 按以下方式填充了 rbuf

  1. 来自进程 0 的 [1] 被放置在索引 0 处。
  2. 来自进程 1 的 [2 2] 被放置在索引 1 处开始。
  3. 来自进程 2 的 [3 3 3] 被放置在索引 3 处开始。
  4. 来自进程 3 的 [4 4 4 4] 被放置在索引 6 处开始。

rbuf 中剩余的零值是未初始化的内存。

为了获得你期望的结果 [1 2 2 3 3 3 4 4 4 4] ,你需要在执行 Gatherv 之后 将接收到的数据块复制到一个新的数组中:

from mpi4py import MPI
import numpy as np

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

send_array = np.ones(rank + 1).astype(int) * (rank + 1)

print(rank, send_array)

if rank == 0:
    gather_size = np.array([sum([i + 1 for i in range(size)])])
    print(gather_size)

    rbuf = np.zeros(gather_size[0]).astype(int)
else:
    gather_size = None
    rbuf = None

comm.Gatherv(sendbuf=send_array, recvbuf=(rbuf, (1, 2, 3, 4), (0, 1, 3, 6), MPI.INT), root=0)

if rank == 0:
    result = np.concatenate([rbuf[displs[i]:displs[i] + recvcounts[i]] for i in range(size)])
    print(result, len(result))

这段代码将创建一个新的 result 数组,并将接收到的数据块从 rbuf 复制到 result 中,从而产生你期望的结果。

标签:python,numpy,mpi,mpi4py
From: 78785836

相关文章

  • SQL 命令在手动运行时工作正常(SQL Developer),但在 Python 的 oracledb 模块中给出 ORA-
    我正在使用OracleSQL数据库,并且我想运行该命令ALTERSESSIONSETNLS_DATE_FORMAT='YYYY-MM-DD';当我从SQLDeveloper应用程序手动运行它时,它工作正常。但是,当我使用oracledb模块从Python运行它时,出现以下错误:ErrorrunningSQLscript:ORA-00922:mi......
  • 在pip包中分发pythonnet dll类型信息
    我已经能够使用C#通过以下方式加载pythonnetdll:fromimportlib.resourcesimportpathimportsys#Assuming'my_package.lib'isthesub-packagecontainingtheDLLswithpath('pyrp.lib','')aslib_path:sys.path.append......
  • 尝试使用 pyinstaller 将 python 文件转换为可执行文件时出现 TypeError
    稍后的目的是通过命令行向GPT4all发送问题并将答案存储在文本文档中。我想将阻止代码转换为exe,但它产生了TypeError。这是到目前为止的代码:fromgpt4allimportGPT4Allmodel=GPT4All("Meta-Llama-3-8B-Instruct.Q4_0.gguf",device='cpu')#downloads/loads......
  • 使用 Python-PlexAPI 获取 plex 上所有好友的关注列表
    有关如何接收我的plex服务器上所有用户的监视列表的任何提示。我正在根据一些规则创建自动删除,其中一个规则是,如果电影位于用户观看列表中,则不应删除该电影。我遇到了麻烦,因为所有与观看列表相关的内容都在MyPlexAccount上。lexapi.myplex.MyPlexAccount具有我的用......
  • 如何在 Python 中查看与 Azure OpenAI 助手关联的所有上传文件?
    我正在使用Python对文档中的问题进行基准测试,并在jupyter笔记本中实例化了我的助手。我想确认助手是否有我上传的文件,但似乎找不到有关此功能将使用什么功能的文档。使用适用于AzureOpenAI的最新版本的PythonAPI。目前,无法使用AzureOpenAI的PythonAPI直接查看......
  • 创建具有标量特征和 N 维坐标向量特征的机器学习 Numpy 数组
    我正在尝试为ML程序格式化我的数据。有33,000个事件,每个事件有3个我想考虑的东西:质量、能量、坐标。质量的形状为(33000,),看起来像:[188.9189.0125.7...127.4201.0210.1]。能量也是(33000,)并且看起来相同:[123...8910]。然后,我还有一个形状为(33000,......
  • 如何在Python中计算小数?
    我正在创建一个计算器来用python计算企业的利润,但到目前为止我只能使用整数。这是我的代码示例:Gross=int(input("PleaseentertotalGrossRevenuefortheFiscalYear"))NetTaxes=int(Gross)*0.1所以我将会计年度的总收入乘以按“税率”计算,但我只能使用......
  • Numpy:将掩码应用于值,然后取平均值,但并行
    我有一个1dnumpy值数组:v=np.array([0,1,4,0,5])此外,我有一个2dnumpy布尔掩码数组(在生产中,有数百万个掩码):m=np.array([[True,True,False,False,False],[True,False,True,False,True],[True,True,True,True,True],])我想将......
  • 如何使用 Python 打开 Google Firestore 上的特定数据库?
    我正在使用Firebase并使用以下代码从Firestore设置/检索文档:importfirebase_adminfromfirebase_adminimportcredentials,firestorecred=credentials.ApplicationDefault()firebase_admin.initialize_app(cred,options={"projectId":"huq-jimbo"})fires......
  • 如何使用 Python 和 Numpy 重现 Matlab 文件读取以解码 .dat 文件?
    我有一个Matlab脚本,可以读取编码的.dat文件,对其进行解码并保存。我试图使用numpy将其转换为Python。我发现对于同一个文件,我得到不同的输出结果(python数字没有意义)。该代码最初作为从串行端口读取的脚本的一部分运行,因此是数据的结构。我首先认为位移是问题所在,因为......