การหาค่าไอเก็นน้อยที่สุดของเมทริกซ์กระจัดกระจายขนาดใหญ่ช้ากว่า SciPy มากกว่า 100 เท่าใน Octave


12

ฉันพยายามคำนวณ eigenvector เพียงไม่กี่ (5-500) ที่สอดคล้องกับค่าลักษณะเฉพาะขนาดเล็กที่สุดของเมทริกซ์กระจัดกระจาย - สมมาตรขนาดใหญ่ (สูงสุด 30000x30000) โดยน้อยกว่า 0.1% ของค่าที่ไม่ใช่ศูนย์

ขณะนี้ฉันกำลังใช้ scipy.sparse.linalg.eigsh ในโหมด shift-invert (sigma = 0.0) ซึ่งฉันคิดว่าผ่านการโพสต์ต่างๆในหัวข้อเป็นวิธีที่ต้องการ อย่างไรก็ตามอาจใช้เวลาถึง 1 ชั่วโมงในการแก้ปัญหาในกรณีส่วนใหญ่ ในทางกลับกันฟังก์ชั่นนั้นเร็วมากถ้าฉันขอค่าลักษณะเฉพาะที่ใหญ่ที่สุด (วินาทีย่อยในระบบของฉัน) ซึ่งคาดว่าจากเอกสาร

เนื่องจากฉันคุ้นเคยกับ Matlab มากขึ้นจากการทำงานฉันพยายามแก้ไขปัญหาใน Octave ซึ่งให้ผลลัพธ์แบบเดียวกันกับฉันโดยใช้ eigs (sigma = 0) ในเวลาเพียงไม่กี่วินาที (ช่วงย่อย 10 วินาที) เนื่องจากฉันต้องการทำการกวาดพารามิเตอร์ของอัลกอริธึมรวมถึงการคำนวณ eigenvector การเพิ่มเวลาแบบนั้นน่าจะเป็นเรื่องที่ดีสำหรับไพ ธ อนเช่นกัน

ฉันก่อนเปลี่ยนพารามิเตอร์ (โดยเฉพาะอย่างยิ่งความอดทน) แต่นั่นไม่ได้เปลี่ยนแปลงมากใน timescales

ฉันใช้ Anaconda บน Windows แต่พยายามที่จะเปลี่ยน LAPACK / BLAS ที่ใช้โดย scipy (ซึ่งเป็นอาการปวดมาก) จาก mkl (Anaconda เริ่มต้น) เป็น OpenBlas (ใช้โดย Octave ตามเอกสารประกอบ) แต่ไม่เห็นการเปลี่ยนแปลงใน ประสิทธิภาพ.

ฉันไม่สามารถทราบได้ว่ามีบางสิ่งที่เปลี่ยนแปลงเกี่ยวกับ ARPACK ที่ใช้แล้วหรือยัง?

ฉันอัปโหลด testcase สำหรับรหัสด้านล่างไปยังดรอปบ็อกซ์โฟลเดอร์ต่อไปนี้: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0

ในงูหลาม

import numpy as np
from scipy.sparse import csr_matrix, csc_matrix, linalg, load_npz   
M = load_npz('M.npz')
evals, evecs = linalg.eigsh(M,k=6,sigma=0.0)

ในระดับแปดเสียง:

M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);

ความช่วยเหลือใด ๆ ที่เป็นประโยชน์!

ตัวเลือกเพิ่มเติมบางอย่างที่ฉันลองใช้โดยอ้างอิงจากความคิดเห็นและข้อเสนอแนะ:

ระดับแปดเสียง: eigs(M,6,0)และeigs(M,6,'sm')ให้ผลลัพธ์เดียวกันกับฉัน:

[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]

ในขณะที่eigs(M,6,'sa',struct('tol',2))มาบรรจบกัน

[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933] 

เร็วกว่ามาก แต่ถ้าค่าความคลาดเคลื่อนสูงกว่า 2 มิฉะนั้นจะไม่รวมกันเลยและค่าจะแตกต่างกันอย่างมาก

Python: eigsh(M,k=6,which='SA')และeigsh(M,k=6,which='SM')ทั้งคู่ไม่ได้มาบรรจบกัน (ข้อผิดพลาด ARPACK เมื่อไม่มีการลู่เข้าถึง) eigsh(M,k=6,sigma=0.0)ให้ค่าลักษณะเฉพาะบางอย่างเท่านั้น(หลังจากผ่านไปเกือบหนึ่งชั่วโมง) ซึ่งต่างจากอ็อกเทฟสำหรับค่าที่เล็กที่สุด (พบ 1 ค่าเล็ก ๆ เพิ่มเติม):

[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]

หากความอดทนสูงพอฉันก็จะได้ผลลัพธ์eigsh(M,k=6,which='SA',tol='1')เช่นกันซึ่งมาใกล้ ๆ กับค่าที่ได้รับอื่น ๆ

[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]

อีกครั้งด้วยค่าลักษณะเฉพาะจำนวนน้อย เวลาในการคำนวณยังคงอยู่เกือบ 30 นาที ในขณะที่ค่าน้อยมากที่แตกต่างกันอาจเข้าใจได้เนื่องจากพวกเขาอาจเป็นตัวแทนของทวีคูณของ 0 ความหลากหลายที่แตกต่างกันทำให้ฉันยุ่งเหยิง

นอกจากนี้ดูเหมือนว่าจะมีความแตกต่างพื้นฐานบางอย่างใน SciPy และ Octave ซึ่งฉันยังไม่สามารถเข้าใจได้


2
1 - ฉันคิดว่าคุณตั้งใจจะใส่เครื่องหมายวงเล็บ [evals, evecs] ในรหัสระดับแปดเสียงหรือไม่? 2 - คุณสามารถรวมตัวอย่างเล็ก ๆ สำหรับ M ได้ไหม หรืออาจเป็นสคริปต์ตัวสร้างสำหรับหนึ่งถ้าเป็นไปได้?
Nick J

1 - ใช่แน่นอนฉันแก้ไขโพสต์ของฉัน 2 - ฉันลองใช้ประสิทธิภาพของเมทริกซ์ย่อยของข้อมูลของฉันแล้วและดูเหมือนว่าอ็อกเทฟจะเร็วกว่าเสมอ แต่สำหรับเมทริกซ์ขนาดเล็กที่ต่ำกว่า 5,000x5000 มันเป็นเพียงปัจจัย 2-5 เท่าเหนือกว่ามันน่าเกลียดมาก และเนื่องจาก "ข้อมูลจริง" ของมันฉันไม่สามารถให้สคริปต์ตัวสร้าง มีวิธีมาตรฐานในการอัปโหลดตัวอย่างหรือไม่? เนื่องจาก sparsity ทำให้ไฟล์ npz มีขนาดเล็กพอสมควร
Spacekiller23

ฉันเดาว่าคุณสามารถแชร์ลิงก์ไปยังที่เก็บข้อมูลบนคลาวด์ได้
Patol75

ขอบคุณ. ฉันรวมลิงค์ดรอปบ็อกซ์ในโพสต์ต้นฉบับและอัปเดตรหัสเป็นตัวอย่างการทำงาน
Spacekiller23

1
ฉันทดสอบบน Matlab R2019b และใช้เวลา 84 วินาทีเทียบกับ 36.5 นาทีใน Python 3.7, Scipy 1.2.1 (เร็วกว่า 26 เท่า)
Bill

คำตอบ:


1

การคาดเดาและความคิดเห็นเนื่องจากฉันไม่มี Matlab / Octave:

ในการหาค่าลักษณะเฉพาะขนาดเล็กของเมทริกซ์สมมาตรที่มีค่าลักษณะเฉพาะ> = 0 เช่นเดียวกับคุณสิ่งต่อไปนี้คือ waaay เร็วกว่า shift-invert:

# flip eigenvalues e.g.
# A:     0 0 0 ... 200 463
# Aflip: 0 163 ... 463 463 463
maxeval = eigsh( A, k=1 )[0]  # biggest, fast
Aflip = maxeval * sparse.eye(n) - A
bigevals, evecs = eigsh( Aflip, which="LM", sigma=None ... )  # biggest, near 463
evals = maxeval - bigevals  # flip back, near 463 -> near 0
# evecs are the same

eigsh( Aflip )สำหรับ eigenpairs ใหญ่เร็วกว่า shift-invert สำหรับเล็กเพราะA * xเร็วกว่าsolve()shift-invert ที่ต้องทำ Matlab / Octave สามารถทำสิ่งนี้ได้Aflipโดยอัตโนมัติหลังจากการทดสอบอย่างรวดเร็วสำหรับ Cholesky
คุณสามารถทำงานeigsh( Aflip )ใน Matlab / Octave ได้หรือไม่?

ปัจจัยอื่น ๆ ที่อาจส่งผลต่อความแม่นยำ / ความเร็ว:

ค่าเริ่มต้นของ Arpack สำหรับเวกเตอร์เริ่มต้นv0คือเวกเตอร์แบบสุ่ม ฉันใช้v0 = np.ones(n)ซึ่งอาจจะแย่สำหรับบางคนAแต่ทำซ้ำได้ :)

นี้Aเมทริกซ์เกือบ sigular ว่าA * ones~ 0

Multicore: scipy-arpack กับ openblas / Lapack ใช้ ~ 3.9 จาก 4 คอร์ใน iMac ของฉัน Matlab / Octave ใช้คอร์ทั้งหมดหรือไม่


นี่คือค่าลักษณะเฉพาะของ Scipy-Arpack สำหรับหลาย ๆ ตัวkและtolgreipped จาก logfiles ภายใต้gist.github :

k 10  tol 1e-05:    8 sec  eigvals [0 8.5e-05 0.00043 0.0014 0.0026 0.0047 0.0071 0.0097 0.013 0.018] 
k 10  tol 1e-06:   44 sec  eigvals [0 3.4e-06 2.8e-05 8.1e-05 0.00015 0.00025 0.00044 0.00058 0.00079 0.0011] 
k 10  tol 1e-07:  348 sec  eigvals [0 3e-10 7.5e-07 7.6e-06 1.2e-05 1.9e-05 2.1e-05 4.2e-05 5.7e-05 6.4e-05] 

k 20  tol 1e-05:   18 sec  eigvals [0 5.1e-06 4.5e-05 0.00014 0.00023 0.00042 0.00056 0.00079 0.0011 0.0015 0.0017 0.0021 0.0026 0.003 0.0037 0.0042 0.0047 0.0054 0.006
k 20  tol 1e-06:   73 sec  eigvals [0 5.5e-07 7.4e-06 2e-05 3.5e-05 5.1e-05 6.8e-05 0.00011 0.00014 0.00016 0.0002 0.00025 0.00027 0.0004 0.00045 0.00051 0.00057 0.00066
k 20  tol 1e-07:  267 sec  eigvals [-4.8e-11 0 7.5e-07 7.6e-06 1e-05 1.9e-05 2e-05 2.2e-05 4.2e-05 5.1e-05 5.8e-05 6.4e-05 6.9e-05 8.3e-05 0.00011 0.00012 0.00013 0.00015

k 50  tol 1e-05:   82 sec  eigvals [-4e-13 9.7e-07 1e-05 2.8e-05 5.9e-05 0.00011 0.00015 0.00019 0.00026 0.00039 ... 0.0079 0.0083 0.0087 0.0092 0.0096 0.01 0.011 0.011 0.012
k 50  tol 1e-06:  432 sec  eigvals [-1.4e-11 -4e-13 7.5e-07 7.6e-06 1e-05 1.9e-05 2e-05 2.2e-05 4.2e-05 5.1e-05 ... 0.00081 0.00087 0.00089 0.00096 0.001 0.001 0.0011 0.0011
k 50  tol 1e-07: 3711 sec  eigvals [-5.2e-10 -4e-13 7.5e-07 7.6e-06 1e-05 1.9e-05 2e-05 2.2e-05 4.2e-05 5.1e-05 ... 0.00058 0.0006 0.00063 0.00066 0.00069 0.00071 0.00075

versions: numpy 1.18.1  scipy 1.4.1  umfpack 0.3.2  python 3.7.6  mac 10.10.5 

Matlab / Octave เหมือนกันหรือไม่? ถ้าไม่ใช่การเดิมพันทั้งหมดจะถูกปิด - ตรวจสอบความถูกต้องก่อนจากนั้นเร่งความเร็ว

ทำไมค่าลักษณะเฉพาะโยกเยกมาก? Tiny <0 สำหรับเมทริกซ์ที่ไม่เป็นลบแน่นอนซึ่งเป็นสัญญาณของ ข้อผิดพลาด roundoffแต่เคล็ดลับปกติของการเปลี่ยนแปลงเล็ก ๆA += n * eps * sparse.eye(n)ไม่ได้ช่วยอะไรเลย


สิ่งนี้Aมาจากไหนปัญหาอะไรบ้าง คุณสามารถสร้างที่คล้ายกันAเล็กกว่าหรือแยกคำ?

หวังว่านี่จะช่วยได้


ขอบคุณสำหรับข้อมูลของคุณและขออภัยสำหรับการตอบกลับล่าช้า (มาก) โครงการที่ฉันใช้สำหรับโครงการนี้เสร็จสมบูรณ์แล้ว แต่ฉันยังสงสัยอยู่ดังนั้นฉันจึงตรวจสอบ น่าเศร้าค่าลักษณะเฉพาะใน Ocatve ปรากฎต่างกันสำหรับ k = 10 ฉันพบ [-2.5673e-16 -1.2239e-18 7.5420e-07 7.5622e-06 1.0189e-05 1.8725e-05 2.0265e-05 2.1568e- 05 4.2458e-05 5.1030e-05] ซึ่งเป็นอิสระจากค่าเผื่อในช่วง 1e-5 ถึง 1e-7 ดังนั้นจึงมีความแตกต่างอื่นที่นี่ คุณไม่คิดว่ามันแปลกที่ scipy (รวมถึงข้อเสนอแนะของคุณ) ให้ค่าเล็กน้อยต่างกันขึ้นอยู่กับจำนวนของค่าที่สอบถาม?
Spacekiller23

@ Spacekiller23 นี่เป็นข้อผิดพลาดตอนนี้ได้รับการแก้ไขใน scipy 1.4.1 (ดูscipy / problems / 11198 ); คุณตรวจสอบเวอร์ชั่นของคุณได้ไหม นอกจากนี้ยังtolยุ่งสำหรับค่าลักษณะเฉพาะขนาดเล็ก - ถามคำถามใหม่เกี่ยวกับว่าถ้าคุณต้องการแจ้งให้เราทราบ
ปฏิเสธ

1

ฉันรู้ว่านี่เก่าแล้ว แต่ฉันมีปัญหาเดียวกัน คุณตรวจสอบที่นี่ ( https://docs.scipy.org/doc/scipy/reference/tutorial/arpack.html ) หรือไม่

ดูเหมือนว่าเมื่อคุณตั้งค่า sigma เป็นจำนวนต่ำ (0) คุณควรตั้งค่าที่ = 'LM' แม้ว่าคุณจะต้องการค่าต่ำ นี่เป็นเพราะการตั้งค่า sigma แปลงค่าที่คุณต้องการ (ต่ำในกรณีนี้) ให้สูงและคุณยังสามารถใช้ประโยชน์จากวิธีการ 'LM' ซึ่งเร็วกว่ามากเพื่อให้ได้สิ่งที่คุณต้องการ )


สิ่งนี้เปลี่ยนประสิทธิภาพสำหรับคุณหรือไม่ นั่นจะเป็นการประหลาดใจสำหรับฉัน ฉันรู้ว่าลิงค์ที่คุณโพสต์และฉันก็ระบุอย่างชัดเจนว่า = 'LM' ในตัวอย่างของฉัน เพราะค่าเริ่มต้นสำหรับการตั้งค่าซึ่งเป็น 'LM' ฉันยังคงตรวจสอบอยู่และประสิทธิภาพไม่เปลี่ยนแปลงสำหรับตัวอย่างของฉัน
Spacekiller23

แท้จริงแล้วดูเหมือนว่าจะมีความแตกต่างคล้ายกันตั้งแต่ Python ถึงระดับแปดเสียงสำหรับคุณ ฉันยังมีเมทริกซ์ขนาดใหญ่ที่ฉันพยายามแยกย่อยและลงเอยด้วย eigsh (เมทริกซ์, k = 7, ซึ่ง = 'LM', sigma = 1e-10) แต่เดิมฉันระบุอย่างไม่ถูกต้องว่า = 'SM' คิดว่าฉันต้องทำอย่างนั้นเพื่อให้ได้ค่าลักษณะเฉพาะที่เล็กที่สุดและใช้เวลาตลอดไปในการตอบคำถาม จากนั้นฉันพบบทความนั้นและรู้ว่าคุณเพียงแค่ระบุให้เป็น 'LM' ที่เร็วขึ้นและตั้งค่า k ให้เป็นสิ่งที่คุณต้องการและมันจะเร่งความเร็วของสิ่งต่าง ๆ เมทริกซ์ของคุณเป็นนักเลงจริงหรือเปล่า?
Anthony Gatti

0

ฉันอยากจะบอกก่อนว่าฉันไม่รู้ว่าทำไมผลลัพธ์ที่คุณและ @Bill รายงานนั้นเป็นแบบนั้น ฉันแค่สงสัยว่าeigs(M,6,0)ใน Octave สอดคล้องกับk=6 & sigma=0หรืออาจเป็นอย่างอื่น?

ด้วย scipy ถ้าฉันไม่ให้ซิกม่าฉันจะได้รับผลลัพธ์ในเวลาที่เหมาะสมด้วยวิธีนี้

import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import eigsh
from time import perf_counter
M = np.load('M.npz')
a = csr_matrix((M['data'], M['indices'], M['indptr']), shape=M['shape'])
t = perf_counter()
b, c = eigsh(a, k=50, which='SA', tol=1e1)
print(perf_counter() - t)
print(b)

ฉันไม่แน่ใจว่าสิ่งนี้สมเหตุสมผลหรือไม่

0.4332823531003669
[4.99011753e-03 3.32467891e-02 8.81752215e-02 1.70463893e-01
 2.80811313e-01 4.14752072e-01 5.71103821e-01 7.53593653e-01
 9.79938915e-01 1.14003837e+00 1.40442848e+00 1.66899183e+00
 1.96461415e+00 2.29252666e+00 2.63050114e+00 2.98443218e+00
 3.38439528e+00 3.81181747e+00 4.26309942e+00 4.69832271e+00
 5.22864462e+00 5.74498014e+00 6.22743988e+00 6.83904055e+00
 7.42379697e+00 7.97206446e+00 8.62281827e+00 9.26615266e+00
 9.85483434e+00 1.05915030e+01 1.11986296e+01 1.18934953e+01
 1.26811461e+01 1.33727614e+01 1.41794599e+01 1.47585155e+01
 1.55702295e+01 1.63066947e+01 1.71564622e+01 1.78260727e+01
 1.85693454e+01 1.95125277e+01 2.01847294e+01 2.09302671e+01
 2.18860389e+01 2.25424795e+01 2.32907153e+01 2.37425085e+01
 2.50784800e+01 2.55119112e+01]

วิธีเดียวที่ฉันพบว่าใช้ sigma และรับผลลัพธ์ในเวลาที่เหมาะสมคือให้ M เป็น LinearOperator ฉันไม่คุ้นเคยกับสิ่งนี้มากนัก แต่จากสิ่งที่ฉันเข้าใจว่าการใช้งานของฉันแสดงถึงเมทริกซ์เอกลักษณ์ซึ่งเป็นสิ่งที่ M ควรจะเป็นหากไม่ได้ระบุไว้ในการโทร เหตุผลสำหรับสิ่งนี้คือแทนที่จะทำการแก้ปัญหาโดยตรง (การสลายตัวของ LU) สคิปปีจะใช้ตัวแก้ซ้ำ ๆ ซึ่งอาจเหมาะสมกว่า เป็นการเปรียบเทียบถ้าคุณให้M = np.identity(a.shape[0])ซึ่งควรจะเหมือนกันแน่นอนแล้ว eigsh ใช้เวลาตลอดไปเพื่อให้ได้ผลลัพธ์ โปรดทราบว่าวิธีการนี้ใช้ไม่ได้หากsigma=0มีให้ แต่ฉันไม่แน่ใจsigma=0ว่ามีประโยชน์จริงๆเหรอ?

import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import eigs, eigsh, LinearOperator
from time import perf_counter


def mv(v):
    return v


M = np.load('M.npz')
a = csr_matrix((M['data'], M['indices'], M['indptr']), shape=M['shape'])
t = perf_counter()
b, c = eigsh(a, M=LinearOperator(shape=a.shape, matvec=mv, dtype=np.float64),
             sigma=5, k=50, which='SA', tol=1e1, mode='cayley')
print(perf_counter() - t)
print(np.sort(-5 * (1 + b) / (1 - b)))

อีกครั้งไม่มีความคิดว่ามันถูกต้อง แต่แตกต่างจากเมื่อก่อนแน่นอน มันจะเป็นการดีถ้าคุณได้รับข้อมูลจากใครบางคนจาก scipy

1.4079377939924598
[3.34420263 3.47938816 3.53019328 3.57981026 3.60457277 3.63996294
 3.66791416 3.68391585 3.69223712 3.7082205  3.7496456  3.76170023
 3.76923989 3.80811939 3.81337342 3.82848729 3.84137264 3.85648208
 3.88110869 3.91286153 3.9271108  3.94444577 3.97580798 3.98868207
 4.01677424 4.04341426 4.05915855 4.08910692 4.12238969 4.15283192
 4.16871081 4.1990492  4.21792125 4.24509036 4.26892806 4.29603036
 4.32282475 4.35839271 4.37934257 4.40343219 4.42782208 4.4477206
 4.47635849 4.51594603 4.54294049 4.56689989 4.58804775 4.59919363
 4.63700551 4.66638214]

ขอบคุณสำหรับข้อมูลและข้อเสนอแนะของคุณ ฉันลองทำบางสิ่งเพื่อให้คำตอบกับคะแนนของคุณ 1. งานในมือของฉันต้องการค้นหาค่าลักษณะเฉพาะน้อยที่สุด / เวกเตอร์ ดังนั้นวิธีการใช้ sigma = 0 จะได้รับแม้กระทั่งในเอกสาร SciPy: docs.scipy.org/doc/scipy/reference/tutorial/arpack.html 2. ฉันลองใช้ตัวเลือกเพิ่มเติมซึ่งฉันแก้ไขเป็นคำถามต้นฉบับ 3. เมื่อฉันเข้าใจสารคดีของ Octave และ SciPy, eigs (M, 6,0) และ k = 6, simga = 0 ควรเหมือนกัน
Spacekiller23

4. เนื่องจากเมทริกซ์ของฉันเป็นจริงและกำลังสองฉันคิดว่าไม่ควรมีตัวเลือก SA และ SM ต่างกัน แต่อย่างน้อยก็มีการคำนวณอย่างน้อย ฉันมาผิดทางที่นี่หรือเปล่า? โดยรวมแล้วหมายถึงคำถามเพิ่มเติม แต่ไม่มีคำตอบหรือคำตอบที่ถูกต้องจากฉัน
Spacekiller23
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.