2013-08-17 28 views
5

Khi tôi bắt đầu làm việc với MATLAB trước đây trong trường đại học, giám sát viên của tôi sẽ giết tôi nếu anh ta thấy bất kỳ vòng lặp không cần thiết (anh ta sẽ yêu cầu trao đổi nó cho kron hoặc bất kỳ thao tác chỉ mục nào có thể). Sau đó, tôi đã cố gắng tránh càng nhiều càng tốt bất kỳ vòng lặp nào trên MATLAB, tìm kiếm MATLAB tối nhất mã hóa các cách để làm phép màu đen thay vì một vòng lặp đơn giản.Cellfun so với Simple Matlab Loop hiệu suất

Và một ngày tôi phát hiện ra cellfun, khiến sự kỳ diệu màu đen khá đơn giản hơn, tôi có thể thay đổi nhiều vòng làm việc với các tế bào và cellfun kết hợp, nhưng một ngày nào đó tôi thấy một post about cellfun mà làm cho tôi thắc mắc nếu thừa hưởng kiến ​​thức matlab của tôi là sự thật , đó là: rằng vòng lặp MATLAB sẽ luôn chậm hơn một hàm được biên dịch sẵn có, đó là điều tôi đã có rất nhiều niềm tin. Tôi đã thử nghiệm nó trong một trong những triển khai của tôi và trên thực tế, cho vòng lặp sẽ nhanh hơn! Tôi đã như thế, OMG, tất cả những ngày đó làm cho mã không rõ ràng lãng phí vì không có gì hahaha. Kể từ ngày đó, tôi đã ngừng làm việc chăm chỉ để cố gắng tối ưu hóa mã MATLAB, thông thường nó phụ thuộc vào từng trường hợp và như vậy.

Hôm nay tôi saw this answer, nhớ nỗ lực của tôi để tránh nhiều vòng lặp MATLAB càng tốt (Tôi không biết liệu tác giả đó có tránh được hiệu suất hay không), nhưng dù sao nó nhắc tất cả điều hiệu suất vòng lặp MATLAB này). Và một câu hỏi đến với tâm trí của tôi: Cellfun có tốt hơn so với các vòng không? Khi nào điều đó đúng?

+1

Đối với câu trả lời của tôi mà bạn đã đề cập: có, tôi cố gắng tránh các vòng lặp 'for', giống như bạn làm (hoặc thường làm) và động lực của tôi là hiệu suất. Tôi nghĩ (hoặc được sử dụng để suy nghĩ?) Đó là sự thật rằng 'for' vòng thường chậm hơn và nên tránh. –

+0

Rõ ràng 'cellfun' chậm hơn trừ trường hợp đặc biệt. Xem http://www.mathworks.com/matlabcentral/answers/42335 và http: //www.mathworks.com/matlabcentral/newsreader/view_thread/301894 –

+0

@LuisMendo Vâng, chính xác! Nhưng tiếc là 'cellfun' với các chức năng ẩn danh xử lý thường chậm hơn các vòng lặp' for' ... điều này sẽ khiến tôi chán nản vì nỗ lực không có gì. Cảm ơn bạn đã tham khảo. – Werner

Trả lời

8

Nếu hiệu suất là yếu tố chính bạn nên tránh sử dụng các tế bào, vòng lặp hoặc cellfun/arrayfun. Thường thì nhanh hơn nhiều khi sử dụng thao tác vectơ (giả sử điều này là có thể).

Mã dưới đây mở rộng trên ví dụ thêm của Werner với các mảng mảng và mảng hoạt động mảng tiêu chuẩn.

Kết quả là:

  • di Vòng Time - 0,1679
  • Cellfun Time - 2,9973
  • Vòng Mảng Time - 0,0465
  • Mảng Time - 0,0019

Code:

nTimes = 1000; 
nValues = 1000; 
myCell = repmat({0},1,nValues); 
output = zeros(1,nValues); 

% Basic operation 
tic; 
for k=1:nTimes 
    for m=1:nValues 
    output(m) = myCell{m} + 1; 
    end 
end 
cell_loop_timeAdd=toc;  
fprintf(1,'Cell Loop Time %0.4f\n', cell_loop_timeAdd); 

tic;   
for k=1:nTimes 
    output = cellfun(@(in) in+1,myCell); 
end 
cellfun_timeAdd=toc; 
fprintf(1,'Cellfun Time %0.4f\n', cellfun_timeAdd); 


myData = repmat(0,1,nValues); 
tic; 
for k=1:nTimes 
    for m=1:nValues 
    output(m) = myData(m) + 1; 
    end 
end 
loop_timeAdd=toc; 
fprintf(1,'Loop Array Time %0.4f\n', loop_timeAdd); 

tic; 
for k=1:nTimes 
    output = myData + 1; 
end 
array_timeAdd=toc; 
fprintf(1,'Array Time %0.4f\n', array_timeAdd); 
+0

Tuyệt vời, điểm tốt và đóng góp. Chỉ một chi tiết: cellfun tic toc cũng chứa hàm fprintf. Điều này sẽ không ảnh hưởng đến kết quả, nhưng dù sao đi nữa… – Werner

4

Tôi sẽ thêm một câu trả lời với kết quả tôi tự kiểm tra, nhưng tôi rất vui nếu mọi người đóng góp kiến ​​thức của họ, đây chỉ là một bài kiểm tra đơn giản mà tôi đã thực hiện.

Tôi đã thử nghiệm các điều kiện sau với kích thước ô 1000 và 1000 vòng (kết quả trong tổng thời gian và có thể tôi sẽ chạy hơn 1000 lần, vì tôi có một chút biến động về kết quả, nhưng dù sao đi nữa , đây không phải là một bài báo khoa học):

  • hoạt động cơ bản (tổng hợp)
    • đơn giản cho vòng lặp: 0,2663 s
    • cellfun: 9,4612 s
  • Chuỗi hoạt động (strcmp)
    • đơn giản cho vòng lặp: 1,3124 s
    • cellfun: 11,8099 s
  • Built-in (isEmpty)
  • không thống nhất (regexp)
    • đơn giản cho vòng lặp: 24,2157 s
    • cellfun (string input): 44.0424 s

Vì vậy, có vẻ như cellfun rằng với chức năng cuộc gọi nặc danh là chậm hơn so với một đơn giản cho vòng lặp, nhưng nếu bạn sẽ sử dụng một phương pháp matlab dựng sẵn, làm điều đó với cellfun và sử dụng nó với báo giá chuỗi . Điều này không nhất thiết phải đúng đối với tất cả các trường hợp, nhưng ít nhất là đối với các chức năng được thử nghiệm.

Các mã kiểm tra thực hiện (Tôi xa là một chuyên gia về tối ưu hóa, vì vậy đây là mã trong trường hợp tôi đã làm điều gì sai):

function ... 
    [loop_timeAdd,cellfun_timeAdd,... 
    loop_timeStr,cellfun_timeStr,... 
    loop_timeBuiltIn,cellfun_timeBuiltInStrInput,... 
    cellfun_timeBuiltyInFcnHandle,... 
    loop_timeNonUniform,cellfun_timeNonUniform] ... 
    = test_cellfun(nTimes,nCells) 

myCell = repmat({0},1,nCells); 
output = zeros(1,nCells); 

% Basic operation 
tic; 
for k=1:nTimes 
    for m=1:nCells 
    output(m) = myCell{m} + 1; 
    end 
end 
loop_timeAdd=toc; 

tic; 
for k=1:nTimes 
    output = cellfun(@(in) in+1,myCell); 
end 
cellfun_timeAdd=toc; 

% String operation 
myCell = repmat({'matchStr'},1,nCells); % Add str that matches 
myCell(1:2:end) = {'dontMatchStr'}; % Add another str that doesnt match 
output = zeros(1,nCells); 

tic; 
for k=1:nTimes 
    for m=1:nCells 
    output(m) = strcmp(myCell{m},'matchStr'); 
    end 
end 
loop_timeStr=toc; 

tic; 
for k=1:nTimes 
    output = cellfun(@(in) strcmp(in,'matchStr'),myCell); 
end 
cellfun_timeStr=toc; 

% Builtin function (isempty) 
myCell = cell(1,nCells); % Empty 
myCell(1:2:end) = {0}; % not empty 
output = zeros(1,nCells); 

tic; 
for k=1:nTimes 
    for m=1:nCells 
    output(m) = isempty(myCell{m}); 
    end 
end 
loop_timeBuiltIn=toc; 

tic; 
for k=1:nTimes 
    output = cellfun(@isempty,myCell); 
end 
cellfun_timeBuiltyInFcnHandle=toc; 

tic; 
for k=1:nTimes 
    output = cellfun('isempty',myCell); 
end 
cellfun_timeBuiltInStrInput=toc; 

% Builtin function (isempty) 
myCell = repmat({'John'},1,nCells); 
myCell(1:2:end) = {'Doe'}; 
output = cell(1,nCells); 

tic; 
for k=1:nTimes 
    for m=1:nCells 
    output{m} = regexp(myCell{m},'John','match'); 
    end 
end 
loop_timeNonUniform=toc; 

tic; 
for k=1:nTimes 
    output = cellfun(@(in) regexp(in,'John','match'),myCell,... 
    'UniformOutput',false); 
end 
cellfun_timeNonUniform=toc; 
0
clear all; 
ntimes = 1000; 

r = 100; 
c = 100; 
d = 100; 
A = rand(r, c, d); 
B = rand(r, c, d); 

tic 
for i = 1:ntimes 
    for j = 1 : d 
     result = A(:, :, j) * B(:, :, j); 
    end 
end 
toc 

A_cell = num2cell(A, [1 2]); 
B_cell = num2cell(B, [1 2]); 
tic 
for i = 1 : ntimes 
    result2 = cellfun(@(x, y) x*y, A_cell, B_cell, 'uni', 0); 
end 
toc 

Hãy thử điều này có thể. Thử nghiệm thêm vài lần nữa. Trung bình, cellfun nhanh hơn vòng lặp kép.

+0

Vòng lặp ngoài mà bạn đã nhận xét với "điều này đang làm gì?" được cho là lặp lại vòng lặp đo được n-lần, để chúng ta giảm độ lệch kết quả và có xu hướng thời gian thực hiện trung bình. Nếu bạn loại bỏ nó, như bạn đã làm, bạn đang so sánh 1 thời gian thực hiện với các vòng lặp khác được lặp lại n-lần. – Werner

+0

@Werner Tôi đã cập nhật mã. Tôi đang tranh cãi vì tôi đang làm những việc tương tự trong dự án của mình. Tôi đã thử nghiệm phiên bản vòng lặp kép trong dự án của tôi và phiên bản cellfun, rằng cellfun nhanh hơn nhiều so với vòng lặp kép .. Tôi không biết tại sao. Nhưng ví dụ này có thể cho thấy rằng cellfun nhanh hơn. – user3390652

+0

So sánh của bạn có vẻ không công bằng, ô có kích thước 1x2 và rand có kích thước 100x100x100. Ngoài ra, có một chút thời gian mà tôi sử dụng MATLAB cuối cùng, nhưng có vẻ như bạn có thể thay đổi 'cho j = 1: d; result = A()… 'bởi' bsxfun' có lẽ sẽ nhanh hơn. – Werner

0

Dưới đây là cách tôi thường sẽ quyết định có giải pháp để sử dụng:

  1. Tôi có thể làm điều đó với các hoạt động ma trận đơn giản? Làm điều đó, nó sẽ là nhanh nhất bạn có thể nhận được và thường dễ đọc hơn.
  2. Tôi có làm điều gì đó đơn giản không? Chuyển đến 3, nếu không hãy truy cập 4.
  3. Tôi có thể làm điều đó với bsxfun không? Làm điều đó, nó sẽ rất nhanh và hy vọng có thể đọc được.
  4. Nếu không sử dụng một đơn giản cho vòng lặp

Như bạn có thể lưu ý, tôi khá nhiều bao giờ sử dụng cellfun cho hiệu suất. Điều này là do logic sau đây:

  1. Cellfun không thực hiện nhanh hơn vòng lặp thường và chủ yếu là tốt để xử lý các ô.
  2. Nếu hiệu suất là quan trọng, bạn có thể muốn tránh các tế bào alltogether, và như vậy bạn sẽ không cần cellfun.
Các vấn đề liên quan