วิธีการ 'คัดลอก' เมทริกซ์โดยไม่ต้องสร้างเมทริกซ์ชั่วคราวในหน่วยความจำที่ทำให้หน่วยความจำล้น


9

โดยการกำหนดเมทริกซ์ให้กับหน่วยความจำที่จัดสรรให้มากขึ้น matlab จะทำซ้ำในขณะที่ 'คัดลอก' และถ้าเมทริกซ์ที่จะคัดลอกมีขนาดใหญ่พอจะมีหน่วยความจำล้น นี่คือตัวอย่างรหัส:

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
    parfor i=1:n
        slice_matrix(:,:,i)=gather(gpuArray(rand(500,500)));
    end
    main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

มีวิธีใดที่จะเพียง 'ชก' slice_matrixลงบนที่main_matไม่มีค่าใช้จ่าย? ขอบคุณล่วงหน้า.

แก้ไข:

โอเวอร์โฟลว์เกิดขึ้นเมื่อmain_matจัดสรรไว้ล่วงหน้า หากmain_matเริ่มต้นด้วยmain_mat=zeros(500,500,1);(ขนาดที่เล็กกว่า) การโอเวอร์โฟลว์จะไม่เกิดขึ้น แต่จะช้าลงเนื่องจากการจัดสรรไม่เสร็จสิ้นก่อนที่เมทริกซ์จะถูกกำหนดเข้าไป สิ่งนี้จะลดประสิทธิภาพลงอย่างมากเมื่อช่วงkเพิ่มขึ้น


1
ในฐานะที่เป็นลูปของคุณ: ก็แนะนำให้ตั้งนอกวงกับparforวงเพื่อเพิ่มประสิทธิภาพ นอกจากนี้parforคัดลอกข้อมูลของคุณไปยังผู้ปฏิบัติงานแต่ละคนแยกกันดังนั้นสมมติว่า 4 คนงานทำซ้ำข้อมูลของคุณสี่ครั้งใน RAM
Adriaan

1
อะไรคือข้อบ่งชี้ของคุณว่า Matlab กำลังทำซ้ำหน่วยความจำจริง ๆ ? คุณใช้memoryฟังก์ชั่นนี้หรือไม่? ผู้จัดการงาน? ข้อผิดพลาดของหน่วยความจำจาก Matlab? มันเกิดบรรทัดอะไรขึ้น
Eliahu Aaron

ในขณะที่คุณสามารถดูที่ฉันแสดงความคิดเห็นในรหัสmain_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)ที่เป็นปัญหาหน่วยความจำล้นเกิดขึ้น มันได้รับการยืนยันเมื่อฉันจัดสรรmain_matล่วงหน้ามันจะล้นถ้าฉันไม่ทำมันจะไม่ Matlab จะส่งคืนข้อผิดพลาดหน่วยความจำไม่เพียงพอ
Gregor Isack

เมทริกซ์ 500x500x2000 ของคุณพอดีกับหน่วยความจำหรือไม่? มัน ~ 4 Gb ดูstackoverflow.com/q/51987892/7328782สำหรับสาเหตุที่ข้อผิดพลาดหน่วยความจำไม่เพียงพอเกิดขึ้นเฉพาะเมื่อเขียนไปยังอาร์เรย์
Cris Luengo

เพื่อให้เข้าใจปัญหาของคุณได้ดีขึ้นคุณสามารถแทรกh=h+slice_matrix(end)ก่อนหน้าmain_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(และเตรียมข้อมูลเบื้องต้นด้วย 0) ได้หรือไม่ ฉันสงสัยว่าบรรทัดที่เพิ่มใหม่นี้จะทำให้เกิดปัญหาหน่วยความจำของคุณแล้ว
Daniel

คำตอบ:


4

ปัญหาหลักคือตัวเลขใช้พื้นที่มากกว่าศูนย์ main_mat=zeros(500,500,2000);ใช้แรมน้อยในขณะที่main_mat = rand(500,500,2000);ใช้เวลามากไม่ว่าคุณจะใช้ GPU หรือ parfor (อันที่จริง parfor จะทำให้คุณใช้ RAM มากกว่า) ดังนั้นนี่ไม่ใช่การบวมของความจำที่ผิดธรรมชาติ ตามลิงก์ของ Daniel ด้านล่างดูเหมือนว่าการกำหนดค่าศูนย์จะสร้างพอยน์เตอร์ไปยังหน่วยความจำเท่านั้นและหน่วยความจำกายภาพจะถูกเติมเมื่อคุณใช้เมทริกซ์สำหรับ "ตัวเลข" เท่านั้น นี่คือการจัดการโดยระบบปฏิบัติการ และเป็นที่คาดหวังสำหรับ Windows, Mac และ Linux ไม่ว่าคุณจะใช้ Matlab หรือภาษาอื่นเช่น C


ตอนนี้ฉันไม่เข้าใจ MATLAB อีกต่อไป เมื่อฉันพิมพ์คำสั่งที่มีการzerosจัดสรรหน่วยความจำเสมือนจริงทั้งหมด แต่ไม่มีการใช้หน่วยความจำ whosแสดงขนาดเท่ากันทั้งสองเมทริกซ์ในขณะที่ระบบปฏิบัติการของฉันแสดงปริมาณการใช้หน่วยความจำที่แตกต่างกัน ฉันลบความคิดเห็นของฉันเพราะคำตอบของคุณไม่ผิดแน่นอน
แดเนียล

3
ฉันพบสิ่งที่อธิบายสิ่งนี้: stackoverflow.com/questions/51987892/…
Daniel

คำตอบที่ดี! ขอบคุณ
JLev

@ Gregor: ฉันเดาว่าจะยืนยันสิ่งนี้ลองใช้onesแทนที่จะzerosทำสิ่งนี้ทำให้แน่ใจได้ว่าหน่วยความจำได้รับการจัดสรรจริงในเวลาที่เรียกใช้ฟังก์ชันที่เกี่ยวข้อง
แดเนียล

เมื่อฉันเข้าใจทุกอย่างถูกต้องข้อสรุปคือ: ไม่มีสำเนาชั่วคราว ข้อยกเว้นหน่วยความจำmain_matไม่เพียงพอเกิดขึ้นเนื่องจากมีการกำหนดค่าที่ไม่ใช่ศูนย์ ก่อนหน้านี้มีการกำหนดหน่วยความจำเสมือน (พื้นที่ที่อยู่) เท่านั้นตอนนี้ถูกกำหนดให้กับหน่วยความจำกายภาพ
แดเนียล

1

การลบparforอาจจะแก้ไขปัญหาของคุณได้

parforไม่มีประโยชน์ที่นั่น MATLAB parforไม่ได้ใช้หน่วยความจำแบบขนานที่ใช้ร่วมกัน (เช่นมันไม่ได้เริ่มเธรดใหม่) แต่เป็นการกระจายหน่วยความจำแบบขนาน (มันเริ่มกระบวนการใหม่) มันถูกออกแบบมาเพื่อแจกจ่ายงานผ่านชุดหรือโหนดผู้ปฏิบัติงาน และแม้ว่ามันจะทำงานภายในหนึ่งโหนด (หรือคอมพิวเตอร์เดสก์ท็อปเดี่ยว) เพื่อกระจายงานผ่านหลายคอร์ แต่ก็ไม่ใช่วิธีที่ดีที่สุดในการทำขนานภายในหนึ่งโหนด

ซึ่งหมายความว่าแต่ละกระบวนการเริ่มต้นโดยparforจำเป็นต้องมีสำเนาของตัวเองslice_matrixซึ่งเป็นสาเหตุของหน่วยความจำจำนวนมากที่ใช้โดยโปรแกรมของคุณ

ดูที่"ตัดสินใจว่าจะใช้เมื่อใดparfor"ในเอกสารประกอบของ MATLAB เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับparforการใช้งาน


1
การลบparfor เป็นวิธีเดียวหรือไม่ การประมวลผลทำงานได้ดีที่สุดเมื่อฉันออกแบบด้วยวิธีนี้เนื่องจากทุกอย่างภายในparforเป็นซีพียูและ GPU อย่างเข้มข้นดังนั้นจึงปรับปรุงประสิทธิภาพอย่างมาก
Gregor Isack

@GregorIsack: parforฉันไปกับรหัสตัวอย่างของคุณไม่ทราบว่าคุณจริงได้มากในการทำงานภายใน ถ้าเป็นเช่นนั้นใช่มันน่าจะมีประโยชน์ - บางทีถ้าslice_matrixไม่ใช่gpuarrayมันจะไม่ถูกคัดลอกในการบ้าน
Cris Luengo

อืมแม้ว่าslice_matrixจะไม่ใช่gpuArrayฉันยังคงมีอาการล้น ฉันจะให้คำถามนี้เปิดขึ้นมาดูว่ามีทางเลือกอื่นหรือไม่ ขอบคุณสำหรับคำตอบว่า!
Gregor Isack

0

ฉันคิดว่ารหัสของคุณเป็นเพียงตัวอย่างรหัสและนั่นrand()เป็นรหัสที่กำหนดเองใน MVE ของคุณ ดังนั้นจึงมีคำแนะนำและเทคนิคเล็กน้อยสำหรับการใช้หน่วยความจำใน matlab

มีตัวอย่างจากคู่มือการฝึกอบรม The MathWorks:

เมื่อกำหนดตัวแปรหนึ่งให้กับอีกตัวแปรหนึ่งใน MATLAB ซึ่งเกิดขึ้นเมื่อส่งพารามิเตอร์ไปยังฟังก์ชัน MATLAB จะสร้างการอ้างอิงไปยังตัวแปรนั้นอย่างโปร่งใส MATLAB แบ่งการอ้างอิงและสร้างสำเนาของตัวแปรนั้นเฉพาะเมื่อโค้ดแก้ไขค่าหนึ่งค่าหรือมากกว่า พฤติกรรมนี้หรือที่เรียกว่าcopy-on-writeหรือlazy-copyingทำให้ค่าใช้จ่ายในการคัดลอกชุดข้อมูลขนาดใหญ่จนกว่ารหัสจะปรับเปลี่ยนค่า ดังนั้นหากรหัสไม่มีการแก้ไขไม่จำเป็นต้องใช้พื้นที่หน่วยความจำเพิ่มเติมและเวลาดำเนินการเพื่อคัดลอกตัวแปร

สิ่งแรกที่ต้องทำคือตรวจสอบประสิทธิภาพ (หน่วยความจำ) ของรหัสของคุณ แม้แต่รหัสของโปรแกรมเมอร์ที่ยอดเยี่ยมก็ยังสามารถปรับให้เหมาะสมกับพลังสมอง (เล็กน้อย) นี่คือคำแนะนำเล็กน้อยเกี่ยวกับประสิทธิภาพของหน่วยความจำ

  • ทำให้การใช้งานของ vectorization nativ ของ MATLAB เช่นsum(X,2), mean(X,2),std(X,[],2)
  • ตรวจสอบให้แน่ใจว่า matlab ไม่จำเป็นต้องขยายเมทริกซ์ ( การขยายโดยนัยมีการเปลี่ยนแปลงเมื่อเร็ว ๆ นี้) มันอาจมีประสิทธิภาพมากกว่าในการใช้bsxfun
  • ใช้ในสถานที่ปฏิบัติงานเช่นx = 2*x+3มากกว่าx = 2*x+3
  • ...

โปรดทราบว่าการใช้หน่วยความจำที่เหมาะสมที่สุดนั้นไม่เหมือนกับถ้าคุณต้องการลดเวลาในการคำนวณ ดังนั้นคุณอาจต้องการพิจารณาลดจำนวนพนักงานหรืองดเว้นการใช้parfor-loop (เนื่องจากparforไม่สามารถใช้หน่วยความจำที่ใช้ร่วมกันได้ไม่มีคุณสมบัติการคัดลอกเมื่อเขียนโดยใช้กล่องเครื่องมือแบบขนาน

หากคุณต้องการที่จะมีการมองใกล้ที่หน่วยความจำ , สิ่งที่มีอยู่และที่สามารถนำมาใช้โดย Matlab feature('memstats')ตรวจสอบ สิ่งที่น่าสนใจสำหรับคุณคือVirtual Memoryนั่นก็คือ

หน่วยความจำทั้งหมดและที่มีอยู่ที่เกี่ยวข้องกับกระบวนการ MATLAB มันถูก จำกัด ด้วยสถาปัตยกรรมโปรเซสเซอร์และระบบปฏิบัติการ หรือใช้คำสั่ง[user,sys] = memoryนี้

โหนดด้านด่วน : Matlab เก็บการฝึกอบรมอย่างต่อเนื่องในหน่วยความจำ คุณต้องมี RAM ขนาดใหญ่บล็อกฟรีสำหรับเมทริกซ์ขนาดใหญ่ นี่คือเหตุผลที่คุณต้องการจัดสรรตัวแปรเนื่องจากการเปลี่ยนแปลงบังคับให้ Matlab ทำการคัดลอกเมทริกซ์ทั้งหมดไปยังจุดที่มีขนาดใหญ่กว่าใน RAM ทุกครั้งที่มันเกินจุดปัจจุบัน

หากคุณมีปัญหาเกี่ยวกับหน่วยความจำจริง ๆคุณอาจต้องการขุดลงไปในศิลปะของชนิดข้อมูล - ตามที่ต้องการในภาษาระดับต่ำกว่า เช่นคุณสามารถลดการใช้หน่วยความจำได้ครึ่งหนึ่งด้วยการใช้ความแม่นยำเดียวโดยตรงตั้งแต่เริ่มต้นmain_mat=zeros(500,500,2000,'single');แต่ก็สามารถใช้งานได้กับrand(...,'single')ฟังก์ชั่นพื้นฐานมากขึ้น - แม้ว่าฟังก์ชัน MATLAB ที่ซับซ้อนมากขึ้นบางส่วนจำเป็นต้องใช้อินพุตของ double type ซึ่งคุณสามารถ upcast อีกครั้ง


0

หากฉันเข้าใจอย่างถูกต้องปัญหาหลักของคุณคือparforไม่อนุญาตให้แบ่งปันหน่วยความจำ คิดว่าคนทำงานส่วนใหญ่ทุกคนเป็นตัวอย่างของ MATLAB ที่แยกจากกัน

มีเพียงหนึ่งวิธีแก้ปัญหาสำหรับสิ่งนี้ที่ฉันรู้ (ที่ฉันไม่เคยลอง) นั่นคือ 'เมทริกซ์ที่ใช้ร่วมกัน' ใน Fileexchange: https://ch.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrix

วิธีแก้ปัญหาเพิ่มเติม: ตามที่คนอื่น ๆ แนะนำ: ลบ parfor เป็นทางออกเดียวรับ ram เพิ่มใช้อาร์เรย์สูง (ซึ่งใช้ harddrives เมื่อ ram ทำงานเต็มอ่านที่นี่ ) แบ่งปฏิบัติการเป็นชิ้นเล็ก ๆ สุดท้าย แต่ไม่ท้ายสุดพิจารณาทางเลือกอื่นนอกเหนือจาก Matlab


0

คุณสามารถใช้รหัสต่อไปนี้ คุณไม่จำเป็นต้องใช้ slice_matrix

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
   parfor i=1:n
       main_mat(:,:,1+(k-1)*n + i - 1) = gather(gpuArray(rand(500,500)));
   end
   %% now you don't need this main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

คุณไม่สามารถทำเช่นนั้นได้ในวงวนวนวน
Gregor Isack

คุณลองทำไหม
mayank1513

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