Làm cách nào để 'sao chép' ma trận mà không tạo ma trận tạm thời trong bộ nhớ gây tràn bộ nhớ?


9

Bằng cách gán một ma trận vào một bộ nhớ được phân bổ lớn hơn nhiều, matlab bằng cách nào đó sẽ nhân đôi nó trong khi 'sao chép' nó và nếu ma trận được sao chép đủ lớn, sẽ có tràn bộ nhớ. Đây là mã mẫu:

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

Có cách nào để "đập" slice_matrixcái main_matmà không cần quá cao không? Cảm ơn trước.

BIÊN TẬP:

Sự cố tràn xảy ra khi main_matđược phân bổ trước. Nếu main_matđược khởi tạo với main_mat=zeros(500,500,1);(kích thước nhỏ hơn), tràn sẽ không xảy ra, nhưng nó sẽ bị chậm lại do việc phân bổ không được thực hiện trước khi ma trận được gán vào nó. Điều này sẽ làm giảm đáng kể hiệu suất khi phạm vi ktăng.


1
Đối với các vòng lặp của bạn: bạn nên đặt vòng lặp bên ngoài thành một parforvòng lặp cho mục đích tối ưu hóa . Ngoài ra, parforsao chép dữ liệu của bạn cho từng công nhân riêng biệt, do đó, giả sử 4 công nhân sẽ sao chép dữ liệu của bạn bốn lần trong RAM.
Adriaan

1
Dấu hiệu của bạn cho thấy Matlab thực sự đang sao chép bộ nhớ là gì? Bạn đang sử dụng memorychức năng? Người quản lý nhiệm vụ? Một lỗi bộ nhớ từ Matlab? Tại dòng mã nào nó đang xảy ra?
Eliahu Aaron

Như bạn có thể thấy nơi tôi đã nhận xét về mã, main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)là nơi xảy ra sự cố tràn bộ nhớ. Nó được xác minh khi tôi phân bổ main_mattrước, nó sẽ tràn, nếu tôi không, nó sẽ không. Matlab sẽ trả về 'hết lỗi bộ nhớ'.
Gregor Isack 16/12/19

Ma trận 500x500x2000 của bạn có phù hợp với bộ nhớ không? Đó là ~ 4 Gb. Xem stackoverflow.com/q/51987892/7328782 để biết lý do tại sao lỗi hết bộ nhớ chỉ có thể xảy ra khi ghi vào mảng.
Cris Luengo

Để hiểu rõ hơn vấn đề của bạn, bạn có thể chèn h=h+slice_matrix(end)trước main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(và khởi tạo h bằng 0) không? Tôi nghi ngờ rằng dòng mới được thêm này sẽ gây ra vấn đề bộ nhớ của bạn.
Daniel

Câu trả lời:


4

Vấn đề chính là số chiếm nhiều không gian hơn số không. main_mat=zeros(500,500,2000);mất ít RAM trong khi main_mat = rand(500,500,2000);mất rất nhiều, bất kể bạn sử dụng GPU hay parfor (thực tế, parfor sẽ khiến bạn sử dụng nhiều RAM hơn). Vì vậy, đây không phải là một ký ức sưng lên bất thường. Theo liên kết của Daniel bên dưới, có vẻ như việc gán các số 0 chỉ tạo con trỏ vào bộ nhớ và bộ nhớ vật lý chỉ được lấp đầy khi bạn sử dụng ma trận cho "số". Điều này được quản lý bởi hệ điều hành. Và nó được mong đợi cho Windows, Mac và Linux, hoặc bạn làm điều đó với Matlab hoặc các ngôn ngữ khác như C.


Ngay bây giờ tôi không còn hiểu MATLAB. Khi tôi gõ các lệnh với zerostoàn bộ bộ nhớ ảo thực sự được cấp phát, nhưng không có bộ nhớ nào được sử dụng. whoshiển thị cùng kích thước cho cả hai ma trận, trong khi hệ điều hành của tôi hiển thị mức tiêu thụ bộ nhớ khác nhau. Tôi đã xóa bình luận của tôi vì câu trả lời của bạn chắc chắn không sai.
Daniel

3
Tôi tìm thấy một cái gì đó giải thích điều này: stackoverflow.com/questions/51987892/ Khăn
Daniel

Câu trả lời chính xác! Cảm ơn.
JLev

@Gregor: Tôi đoán để xác nhận điều này, hãy thử onesthay vì zeros, điều này đảm bảo bộ nhớ được phân bổ thực sự tại thời điểm gọi hàm tương ứng.
Daniel

Khi tôi hiểu mọi thứ đúng, kết luận là: Không có bản sao tạm thời. Ngoại lệ bộ nhớ phát sinh vì main_matđược gán các giá trị khác không. Trước đây chỉ có bộ nhớ ảo (không gian địa chỉ) được gán, giờ đây được gán cho bộ nhớ vật lý.
Daniel

1

Loại bỏ parforsẽ có khả năng khắc phục vấn đề của bạn.

parforkhông có ích ở đó MATLAB parforkhông sử dụng song song bộ nhớ dùng chung (nghĩa là nó không bắt đầu các luồng mới) mà là song song bộ nhớ phân tán (nó bắt đầu các tiến trình mới). Nó được thiết kế để phân phối công việc trên một tập hợp hoặc các nút worker. Và mặc dù nó cũng hoạt động trong một nút (hoặc một máy tính để bàn) để phân phối công việc trên nhiều lõi, nhưng đó không phải là cách tối ưu để thực hiện song song trong một nút.

Điều này có nghĩa là mỗi quá trình được bắt đầu bởi parforcần phải có bản sao riêng slice_matrix, đó là nguyên nhân của số lượng lớn bộ nhớ được sử dụng bởi chương trình của bạn.

Xem "Quyết định khi nào nên sử dụng parfor" trong tài liệu MATLAB để tìm hiểu thêm về parforvà khi nào nên sử dụng nó.


1
Là loại bỏ parfor là cách duy nhất ? Quá trình xử lý hoạt động tốt nhất khi tôi thiết kế theo cách đó, vì mọi thứ bên trong parforđều cần CPU và GPU, do đó nó cải thiện đáng kể hiệu năng.
Gregor Isack

@GregorIsack: Tôi đã đi với mã ví dụ của bạn, không biết bạn thực sự đã làm rất nhiều công việc bên trong parfor. Nếu vậy, thì có, nó có khả năng hữu ích. - Có lẽ nếu slice_matrixkhông phải là gpuarraynó sẽ không được sao chép trong bài tập.
Cris Luengo

Hmmm ngay cả khi slice_matrixkhông phải là một gpuArray, tôi vẫn nhận được triệu chứng tràn. Tôi sẽ để câu hỏi này mở ra, hãy xem liệu có giải pháp thay thế nào không. Cảm ơn vì câu trả lời!
Gregor Isack 16/12/19

0

Tôi giả sử rằng mã của bạn chỉ là mã mẫu và rand()đại diện cho một tùy chỉnh trong MVE của bạn. Vì vậy, có một vài gợi ý và thủ thuật cho việc sử dụng bộ nhớ trong MATLAB.

Có một đoạn trong sổ tay đào tạo The MathWorks:

Khi gán một biến cho một biến khác trong MATLAB, như xảy ra khi truyền tham số vào hàm, MATLAB tạo một tham chiếu trong biến đó. MATLAB phá vỡ tham chiếu và tạo một bản sao của biến đó, chỉ khi mã sửa đổi một hoặc nhiều giá trị teh. Hành vi này, được gọi là sao chép khi ghi hoặc sao chép lười biếng , trì hoãn chi phí sao chép các tập dữ liệu lớn cho đến khi mã sửa đổi một giá trị. Do đó, nếu mã thực hiện không có sửa đổi, không cần thêm dung lượng bộ nhớ và thời gian thực hiện để sao chép các biến.

Điều đầu tiên cần làm là kiểm tra hiệu quả (bộ nhớ) của mã của bạn. Ngay cả mã của các lập trình viên xuất sắc cũng có thể được tối ưu hóa hơn nữa với (một chút) sức mạnh não bộ. Dưới đây là một vài gợi ý về hiệu quả bộ nhớ

  • sử dụng vector hóa nativ của matlab, ví dụ sum(X,2), mean(X,2).std(X,[],2)
  • đảm bảo rằng MATLAB không phải mở rộng ma trận ( mở rộng ngầm đã được thay đổi gần đây). Nó có thể hiệu quả hơn để sử dụngbsxfun
  • sử dụng tại chỗ, ví dụ như x = 2*x+3thay vìx = 2*x+3
  • ...

Xin lưu ý rằng việc sử dụng bộ nhớ tối ưu không giống như bạn muốn giảm thời gian tính toán. Do đó, bạn có thể muốn xem xét giảm số lượng công nhân hoặc không sử dụng parfor-loop. (Vì parforkhông thể sử dụng bộ nhớ dùng chung, không có tính năng sao chép khi ghi bằng cách sử dụng Hộp công cụ song song.

Nếu bạn muốn xem xét kỹ hơn về bộ nhớ của mình , những gì có sẵn và Matlab có thể sử dụng, hãy xem feature('memstats'). Điều thú vị dành cho bạn là bộ nhớ ảo đó là

Tổng số và bộ nhớ khả dụng liên quan đến toàn bộ quá trình MATLAB. Nó bị giới hạn bởi kiến ​​trúc bộ xử lý và hệ điều hành. hoặc sử dụng lệnh này [user,sys] = memory.

Nút bên nhanh : Matlab lưu trữ ma trận nhất quán trong bộ nhớ. Bạn cần phải có một khối lớn RAM miễn phí cho ma trận lớn. Đó cũng là lý do tại sao bạn muốn phân bổ các biến, bởi vì việc thay đổi chúng một cách linh hoạt buộc Matlab sao chép toàn bộ ma trận vào một điểm lớn hơn trong RAM mỗi khi nó vượt xa vị trí hiện tại.

Nếu bạn thực sự có vấn đề về bộ nhớ , bạn có thể chỉ muốn đào sâu vào nghệ thuật của các loại dữ liệu - như được yêu cầu trong các ngôn ngữ cấp thấp hơn. Ví dụ như bạn có thể cắt sử dụng bộ nhớ của bạn trong một nửa bằng cách sử dụng chính xác đơn trực tiếp từ đầu main_mat=zeros(500,500,2000,'single');- btw, điều này cũng làm việc với rand(...,'single')và hàm native hơn - mặc dù một vài trong số các chức năng matlab phức tạp hơn đòi hỏi đầu vào của loại đôi, mà bạn có thể lại u ám.


0

Nếu tôi hiểu chính xác thì vấn đề chính của bạn là parforkhông cho phép chia sẻ bộ nhớ. Hãy nghĩ về mỗi nhân viên parfor như một ví dụ matlab riêng biệt.

Về cơ bản, chỉ có một cách giải quyết cho điều này mà tôi biết (mà tôi chưa bao giờ thử), đó là 'ma trận chia sẻ' trên Fileexchange: https://ch.mathworks.com/matlabcentral/fileexchange/28572- Sharedmatrix

Nhiều giải pháp hơn: như những người khác đề xuất: loại bỏ parfor chắc chắn là một giải pháp, nhận thêm ram, sử dụng mảng cao (sử dụng ổ cứng khi ram chạy đầy đủ, đọc ở đây ), chia các hoạt động trong các phần nhỏ hơn, cuối cùng nhưng không kém phần quan trọng, hãy xem xét một giải pháp khác Matlab.


0

Bạn có thể sử dụng mã sau đây. Bạn thực sự không cần lát_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

Bạn không thể làm điều đó trong một vòng lặp parfor
Gregor Isack

Bạn đã thử chưa?
mayank1513

Có một lý do tại sao tôi di chuyển nó ra khỏi vòng parfoor. Tôi đã không thử chính xác cùng một mã, nhưng tôi biết nó sẽ không hoạt động vì lập chỉ mục.
Gregor Isack
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.