繁体   English   中英

并行化大型(> 30k x 30k)非平方密集矩阵的最小二乘

[英]Parallellize least squares for large (> 30k x 30k) non-square dense matrices

RG = A用于具有形状的密集非结构化矩阵(例如大致) R :(30k x 40k,条目 float32)和G :(40k x 50k,条目 0.0 或 1.0,大致相同)当然A :(30k x 50k,条目浮动32)。

给定AG ,我想找到R的最小二乘解。

我可以使用数百个 CPU 内核、数百 GB 的 RAM 以及一个 A40 GPU。 使用这些资源解决问题的最佳方法是什么? 我在下面的示例中使用 Julia 1.7,但我对其他选项持开放态度!

第一个问题:我能以某种方式利用G的条目只有零和一吗?

尝试将 Julia LinearAlgebra与许多 CPU 一起使用

我尝试了两种方法:“彭罗斯逆”和“右除法”

using LinearAlgebra
@show BLAS.get_num_threads()
# defaults to 8. Can change using BLAS.set_num_threads(N)

# build toy problem (order of magnitude smaller sizes)
R_true = rand(Float32, 3_000, 4_000) 
G = rand([0., 1.], 4_000, 5_000)
# note: using true/false here gives same results but is much slower!
A = R_true * G

# solve toy problem using matrix (right) division
R_fitted_rdiv = A / G

# solve toy problem using Penrose inverse
R_fitted_pinv = (pinv(G') * A')'

首先,设置BLAS.set_num_threads(64) (或任何更大的数字)实际上只会给我BLAS.get_num_threads()返回 32。显然这是一个上限。 第二,

使用 32 个 BLAS 线程实际上比使用 8 个

(例如,在 8 个线程上执行大小为 (4000, 9800) / (8500, 9800) 的右除法需要不到 50 秒,但在 32 个线程上需要超过 55 秒。我多次运行以排除编译时间问题。)我没有不知道为什么会这样或者是否正常。 我怎样才能利用我的计算能力来解决这个问题?

我认为矩阵除法比彭罗斯逆方法快。 这应该预期吗? 我不知道这两个函数对这些输入到底做了什么。 文档说左除 ( \ ) 使用旋转 QR 分解 我找不到用于pinv或右除法 ( / ) 的算法(尽管它可能与\相同,因为它们通过转置矩阵相关)。 我宁愿不要深入研究,因为我在数值线性代数方面的知识非常有限。

问题是对于我的大型矩阵,任何一种方法都需要永远。 有没有办法以某种方式利用我的〜100个核心?

尝试使用 GPU:

使用CUDA.jl ,大小约为 10k 的矩阵可以正常工作,并且需要一分钟来pinv

using CUDA
@time matrix = CUDA.rand(Float32, 10_000, 10_500) # 0.003037 seconds (5 allocations: 160 bytes)
@time pinv(matrix) #  57.417559 seconds (678 allocations: 172.094 KiB)

但是,当我尝试做大约 20k 大小的矩阵时,我立即得到错误InexactError: trunc(Int32, 4811456640) 我认为这是由于CUBLAS 使用 int32 进行索引,即使我不明白为什么在这种情况下会导致错误。 (编辑:它大约是适合 31 位的字节数组的大小。)

尝试对CuArray s 使用右除法会产生错误“DimensionMismatch(“LU 分解矩阵 A 必须是正方形!”)”。 我想我必须手动选择不同的算法? 我不知道它叫什么。 (虽然,对于大型矩阵,它可能仍然会崩溃......?)

总而言之,看起来我不能轻松地使用 Julia 的 GPU 来解决我的问题。 我应该继续尝试使用 GPU 来完成这项任务还是坚持使用许多 CPU?

是的,这确实是我的问题,请不要评论“没有人应该需要这么大的最小二乘”

天真的答案

使用 pytorch,这将需要至少 30GB 的 GPU 内存

import torch
A = torch.randint(0, 2, (50000, 40000), device='cuda', dtype=torch.float32).T
G = torch.randint(0, 2, (50000, 30000), device='cuda', dtype=torch.float32).T
R = torch.lstsq(G.T, A.T)

如果系统可以维持与我的笔记本电脑相同的操作吞吐量,您应该在大约 15 分钟内得到答案。

我建议您尝试扩大尺寸的通用版本,以更好地了解您的系统将如何处理它

def try_it(a,b,c):
  A = torch.randint(0, 2, (a, b), device='cuda', dtype=torch.float32).T
  G = torch.randint(0, 2, (a, c), device='cuda', dtype=torch.float32).T
  R = torch.lstsq(G.T, A.T)

为了确保 GT 和 AT 是连续的,我在生成中转换了维度。

您不能充分利用整数条目。 这种类型的问题在实数上比在整数上更容易解决,因为找到整数解决方案需要您搜索解决方案,而您可以通过代数运算找到真正的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM