簡體   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