Dans Matlab, quand est-il optimal d'utiliser bsxfun?

ma Question: j'ai remarqué que beaucoup de bonnes réponses aux questions de Matlab sur si souvent utiliser la fonction bsxfun . Pourquoi?

Motivation: dans la documentation Matlab pour bsxfun , l'exemple suivant est fourni:

A = magic(5);
A = bsxfun(@minus, A, mean(A))

bien sûr, nous pourrions faire la même opération en utilisant:

A = A - (ones(size(A, 1), 1) * mean(A));

et, en fait, un simple essai de vitesse démontre que la la deuxième méthode est environ 20% plus rapide. Alors pourquoi utiliser la première méthode? Je suppose qu'il y a des circonstances où l'utilisation de bsxfun sera beaucoup plus rapide que l'approche "manuelle". Je serais vraiment intéressé de voir un exemple d'une telle situation et une explication des raisons pour lesquelles il est plus rapide.

aussi, un dernier élément à cette question, encore une fois de la documentation Matlab pour bsxfun : "C = bsxfun (fun,A, B) applique l'opération binaire élément par élément spécifié par le fonction manier fun aux tableaux A et B, avec expansion singleton activée.". Que signifie l'expression "avec une extension singleton permise"?

123
demandé sur George Stocker 2012-10-18 13:31:53

5 réponses

il y a trois raisons pour lesquelles j'utilise bsxfun ( documentation , lien de blog )

  1. bsxfun est plus rapide que repmat (voir ci-dessous)
  2. bsxfun nécessite moins de Dactylographie
  3. utiliser bsxfun , comme utiliser accumarray , me fait me sentir bien au sujet de ma compréhension de Matlab.

bsxfun sera répliquer les tableaux d'entrées le long de leurs "dimensions uniques", c.-à-d. Les dimensions le long desquelles la taille du tableau est 1, de sorte qu'ils correspondent à la taille de la dimension correspondante de l'autre tableau. C'est ce qu'on appelle "l'expasion singleton". En aparté, le singleton dimensions sont celles qui seront supprimées si vous appelez squeeze .

il est possible que pour de très petits problèmes, l'approche repmat est plus rapide - mais à cette taille de réseau, les deux opérations sont si rapides que cela ne fera probablement aucune différence en termes de performance globale. Il ya deux raisons importantes bsxfun est plus rapide: (1) le calcul se produit dans le code compilé, ce qui signifie que la réplication réelle du tableau ne se produit jamais, et (2) bsxfun est l'une des fonctions multithreaded Matlab.

j'ai effectué une comparaison de vitesse entre repmat et bsxfun avec R2012 sur mon ordinateur portable décemment rapide.

enter image description here

pour moi, bsxfun est environ 3 fois plus rapide que repmat . La différence devient plus prononcée si les tableaux deviennent plus grands

enter image description here

le saut dans l'exécution de repmat se produit autour d'une taille de tableau de 1Mb, qui pourrait avoir quelque chose à voir avec la taille de mon Cache processeur - bsxfun ne devient pas aussi mauvais d'un saut, parce qu'il n'a besoin d'allouer le tableau de sortie.

vous trouverez ci-dessous le code que j'ai utilisé pour le timing:

n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
   r = rand(1,i*k);
   for it=1:ntt;
      tic,
      x=bsxfun(@plus,a,r);
      tt(it)=toc;
   end;
   bb(i)=median(tt);
   for it=1:ntt;
      tic,
      y=repmat(a,1,i*k)+repmat(r,10,1);
      tt(it)=toc;
   end;
   rr(i)=median(tt);
end
145
répondu Jonas 2012-10-18 13:25:17

dans mon cas, j'utilise bsxfun parce qu'il m'évite de penser à la colonne ou les questions de rangée.

pour écrire votre exemple:

A = A - (ones(size(A, 1), 1) * mean(A));

je dois résoudre plusieurs problèmes:

1) size(A,1) ou size(A,2)

2) ones(sizes(A,1),1) ou ones(1,sizes(A,1))

3) ones(size(A, 1), 1) * mean(A) ou mean(A)*ones(size(A, 1), 1)

4) mean(A) ou mean(A,2)

quand j'utilise bsxfun , je dois juste résoudre le dernier:

a) mean(A) ou mean(A,2)

vous pourriez penser qu'il est paresseux ou quelque chose, mais quand j'utilise bsxfun , j'ai moins de bogues et I programme plus rapide .

de plus, il est plus court, ce qui améliore la lisibilité vitesse de frappe et .

39
répondu Oli 2012-10-18 20:48:50

question très intéressante! Je suis tombé récemment sur exactement une telle situation en répondant cette question. Considérons le code suivant qui calcule les indices d'une fenêtre coulissante de taille 3 à travers un vecteur a :

a = rand(1e7,1);

tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc

% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;

isequal(idx, idx2)

Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.

ans =

 1

dans ce cas, bsxfun est presque deux fois plus rapide! Il est utile et rapide car il évite l'attribution explicite de la mémoire pour les matrices idx0 et idx1 , les sauvegardant dans la mémoire, puis les lisant à nouveau juste pour les ajouter. Puisque la bande passante mémoire est un atout précieux et souvent le goulot d'étranglement sur les architectures d'aujourd'hui, vous voulez l'utiliser à bon escient et diminuer les besoins en mémoire de votre code pour améliorer les performances.

bsxfun vous permet de faire exactement cela: créer une matrice basée sur l'application d'un opérateur arbitraire à toutes les paires d'éléments de deux vecteurs, au lieu d'opérer explicitement sur deux matrices obtenues en répliquant les vecteurs. C'est-à-dire singleton expansion . Vous pouvez également y penser comme le produit extérieur de BLAS:

v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.

vous multipliez deux vecteurs pour obtenir une matrice. Juste que le produit extérieur n'effectue que la multiplication, et bsxfun peut appliquer des opérateurs arbitraires. Sur le côté, il est très intéressant de voir que bsxfun est aussi rapide que le produit extérieur BLAS. Et BLAS est généralement considéré pour fournir la performance ..

Edit merci au commentaire de Dan, voici un grand article de Loren discutant exactement cela.

16
répondu angainor 2017-05-23 10:30:55

à partir de R2016b, Matlab prend en charge expansion implicite pour une grande variété d'opérateurs, de sorte que dans la plupart des cas, il n'est plus nécessaire d'utiliser bsxfun :

auparavant, cette fonctionnalité était disponible via la fonction bsxfun . Il est maintenant recommandé de remplacer la plupart des utilisations de bsxfun par des appels aux fonctions et opérateurs qui supportent implicite expansion . Comparé à l'utilisation de bsxfun , expansion implicite offre vitesse plus rapide , meilleure utilisation de la mémoire , et amélioration de la lisibilité du code .

il y a une discussion détaillée de Expansion implicite et sa performance sur le blog de Loren. À citation Steve Eddins from MathWorks:

Dans R2016b, implicite expansion fonctionne aussi vite ou plus vite que les bsxfun dans la plupart des cas. Les meilleurs gains de performance pour expansion implicite sont avec de petites tailles de matrice et de tableau. Pour les grandes tailles de matrice, l'expansion implicite tend à être à peu près la même vitesse que bsxfun .

12
répondu nirvana-msu 2016-12-30 16:39:15

les choses ne sont pas toujours cohérentes avec les 3 méthodes communes: repmat , l'extension par l'indexation de uns, et bsxfun . Il devient un peu plus intéressant quand vous augmentez la taille du vecteur encore plus loin. Voir tracé:

comparison

bsxfun devient en fait légèrement plus lent que les deux autres à un moment donné, mais ce qui m'a surpris est si vous augmentez la taille du vecteur encore plus (>éléments de sortie 13E6), bsxfun soudainement redevient plus rapide d'environ 3x. Leurs vitesses semblent sauter par pas et l'ordre n'est pas toujours cohérent. Je pense qu'il pourrait être dépendant de la taille du processeur/mémoire aussi, mais en général je pense que je m'en tiendrais à bsxfun chaque fois que c'est possible.

8
répondu Justin Wong 2014-06-05 08:43:51