Suche…


Bemerkungen

Leistungsengpässe mit dem Profiler erkennen

Der MATLAB Profiler ist ein Werkzeug zum Software-Profiling von MATLAB-Code. Mit dem Profiler ist es möglich, eine visuelle Darstellung der Ausführungszeit und des Speicherverbrauchs zu erhalten.

Der Profiler kann auf zwei Arten ausgeführt werden:

  • Klicken Sie auf die Schaltfläche "Run and Time" in der MATLAB- .m während einige .m Dateien im Editor geöffnet sind (hinzugefügt in R2012b ).

    Schaltfläche im Werkzeugstreifen

  • Programmgesteuert mit:

    profile on
    <some code we want to test>
    profile off
    

Nachfolgend finden Sie einige Beispielcodes und das Ergebnis der Profilerstellung:

function docTest

for ind1 = 1:100
  [~] = var(...
            sum(...
                randn(1000)));
end

spy

Profiler-Ausgabe

Aus den obigen Ausführungen erfahren wir, dass die spy Funktion ungefähr 25% der gesamten Ausführungszeit benötigt. Im Fall von "realem Code" wäre eine Funktion, die einen so hohen Prozentsatz der Ausführungszeit cla , ein guter Kandidat für die Optimierung, im Gegensatz zu Funktionen, die analog zu var und cla deren Optimierung vermieden werden sollte.

Darüber hinaus können Sie auf Einträge in der Spalte Funktionsname klicken, um eine detaillierte Aufgliederung der Ausführungszeit für diesen Eintrag anzuzeigen. Hier ist das Beispiel des Klickens spy :

Internes Timing von "Spion"


Es ist auch möglich, den Speicherverbrauch durch Ausführen des profile('-memory') vor dem Ausführen des Profilers zu profilieren.

Geben Sie hier die Bildbeschreibung ein

Vergleichen der Ausführungszeit mehrerer Funktionen

Die weit verbreitete Kombination aus tic und toc kann eine grobe Vorstellung von der Ausführungszeit einer Funktion oder von Codeausschnitten geben.

Für den Vergleich mehrerer Funktionen sollte es nicht verwendet werden. Warum? Es ist fast unmöglich, für alle Codeausschnitte gleiche Bedingungen bereitzustellen, um sie innerhalb eines Skripts mit der obigen Lösung zu vergleichen. Möglicherweise teilen die Funktionen den gleichen Funktionsraum und die gleichen gemeinsamen Variablen, so dass später genannte Funktionen und Codeausschnitte bereits zuvor initialisierte Variablen und Funktionen nutzen. Außerdem gibt es keine Einsicht, ob der JIT-Compiler diese nachfolgend genannten Snippets gleich behandeln würde.


Die dedizierte Funktion für Benchmarks ist timeit . Das folgende Beispiel veranschaulicht seine Verwendung.

Es gibt das Array A und die Matrix B Es sollte bestimmt werden, welche Zeile von B A am ähnlichsten ist, indem die Anzahl der verschiedenen Elemente gezählt wird.

function t = bench()
    A = [0 1 1 1 0 0];
    B = perms(A);

    % functions to compare
    fcns = {
        @() compare1(A,B);
        @() compare2(A,B);
        @() compare3(A,B);
        @() compare4(A,B);
    };

    % timeit
    t = cellfun(@timeit, fcns);
end

function Z = compare1(A,B)  
    Z = sum(  bsxfun(@eq,  A,B) , 2);
end
function Z = compare2(A,B)  
    Z = sum(bsxfun(@xor, A, B),2);
end
function Z = compare3(A,B)  
    A = logical(A);
    Z = sum(B(:,~A),2) + sum(~B(:,A),2);
end
function Z = compare4(A,B)  
     Z = pdist2( A, B, 'hamming', 'Smallest', 1 );
end

Diese Art von Benchmark wurde erstmals in dieser Antwort gesehen .

Es ist in Ordnung "Single" zu sein!

Überblick:

Der Standarddatentyp für numerische Arrays in MATLAB ist double . double ist eine Gleitkommendarstellung von Zahlen , und dieses Format benötigt 8 Bytes (oder 64 Bits) pro Wert. In einigen Fällen, in denen z. B. nur mit Ganzzahlen gearbeitet wird oder wenn numerische Instabilität kein unmittelbar bevorstehendes Problem ist, ist eine solche hohe Bittiefe möglicherweise nicht erforderlich. Aus diesem Grund wird empfohlen, die Vorteile der single (oder anderer geeigneter Typen ) zu berücksichtigen:

  • Schnellere Ausführungszeit (besonders auf GPUs erkennbar).
  • Die Hälfte des Speicherverbrauchs: kann erfolgreich sein, wenn double aufgrund eines Speichermangels ausfällt. kompakter beim Speichern als Dateien.

Das Konvertieren einer Variablen von einem beliebigen unterstützten Datentyp in einen single erfolgt mithilfe von:

sing_var = single(var);

Einige häufig verwendete Funktionen (z. B. zeros , eye , ones usw. ), die standardmäßig double Werte ausgeben, ermöglichen die Angabe des Typs / der Klasse der Ausgabe.

Konvertieren von Variablen in einem Skript in eine nicht standardmäßige Genauigkeit / Typ / Klasse:

Seit Juli 2016 gibt es keine dokumentierte Möglichkeit, den Standard- MATLAB-Datentyp von double zu ändern.

In MATLAB ahmen neue Variablen normalerweise die Datentypen von Variablen nach, die beim Erstellen verwendet wurden. Um dies zu veranschaulichen, betrachten Sie das folgende Beispiel:

A = magic(3);
B = diag(A);
C = 20*B;
>> whos C
  Name      Size            Bytes  Class     Attributes
  C         3x1                24  double 
A = single(magic(3)); % A is converted to "single"
B = diag(A);
C = B*double(20);     % The stricter type, which in this case is "single", prevails
D = single(size(C));  % It is generally advised to cast to the desired type explicitly.
>> whos C
  Name      Size            Bytes  Class     Attributes
  C         3x1                12  single  

Daher scheint es ausreichend zu sein, mehrere Ausgangsvariablen umzuwandeln / umzuwandeln, damit die Änderung den gesamten Code durchläuft . Dies wird jedoch abgelehnt (siehe unten, Vorbehalte und Gefahren ).

Vorbehalte & Fallstricke:

  1. Wiederholte Konvertierungen werden aufgrund der Einführung von numerischem Rauschen (beim Umwandeln von single zu double ) oder Informationsverlust (beim Umwandeln von double in single oder zwischen bestimmten Ganzzahltypen ) abgeraten , z.

    double(single(1.2)) == double(1.2)   
    ans =
         0
    

    Dies kann etwas gemildert werden , indem typecast . Siehe auch Beachten Sie die Ungenauigkeit von Gleitkommazahlen .

  2. Ausschließlich auf die implizite Datentypisierung zu vertrauen (dh, was MATLAB für die Art der Ausgabe einer Berechnung hält) wird aufgrund verschiedener unerwünschter Auswirkungen abgeraten :

    • Informationsverlust : Wenn ein double erwartet wird, aber eine unvorsichtige Kombination von single und double eine single Genauigkeit ergibt.

    • Unerwartet hoher Speicherverbrauch : Wenn ein single Ergebnis erwartet wird, eine unvorsichtige Berechnung jedoch zu einer double Ausgabe führt.

    • Unnötiger Aufwand beim Arbeiten mit GPUs : Beim Mischen von gpuArray Typen (dh in VRAM gespeicherten Variablen) mit Nicht- gpuArray Variablen (dh, die normalerweise im RAM gespeichert sind) müssen die Daten auf die eine oder andere Weise übertragen werden, bevor die Berechnung ausgeführt werden kann. Dieser Vorgang erfordert Zeit und kann bei wiederholten Berechnungen sehr auffällig sein.

    • Fehler beim Mischen von Gleitkommatypen mit Ganzzahltypen : Funktionen wie mtimes ( * ) sind nicht für gemischte Eingaben von Ganzzahl- und Gleitkommatypen definiert - und es wird ein Fehler mtimes . Funktionen wie times ( .* ) Sind für Integer-Eingaben überhaupt nicht definiert und werden erneut fehlerhaft.

      >> ones(3,3,'int32')*ones(3,3,'int32')
      Error using  * 
      MTIMES is not fully supported for integer classes. At least one input must be scalar.
      
      >> ones(3,3,'int32').*ones(3,3,'double')
      Error using  .* 
      Integers can only be combined with integers of the same class, or scalar doubles.
      

    Zur besseren Lesbarkeit des Codes und zur Verringerung des Risikos unerwünschter Typen wird ein defensiver Ansatz empfohlen , bei dem Variablen explizit in den gewünschten Typ umgewandelt werden.


Siehe auch:

Neuanordnen eines ND-Arrays kann die Gesamtleistung verbessern

In einigen Fällen müssen wir Funktionen auf einen Satz von ND-Arrays anwenden. Schauen wir uns dieses einfache Beispiel an.

A(:,:,1) = [1 2; 4 5];
A(:,:,2) = [11 22; 44 55];
B(:,:,1) = [7 8; 1 2];
B(:,:,2) = [77 88; 11 22];

A =

ans(:,:,1) =

   1   2 
   4   5 

ans(:,:,2) =

   11   22
   44   55

>> B
B =

ans(:,:,1) =

   7   8
   1   2

ans(:,:,2) =

   77   88
   11   22

Beide Matrizen sind 3D. Nehmen wir an, wir müssen Folgendes berechnen:

result= zeros(2,2);
...
for k = 1:2 
   result(i,j) = result(i,j) + abs( A(i,j,k) - B(i,j,k) );
...

if k is very large, this for-loop can be a bottleneck since MATLAB order the data in a column major fashion. So a better way to compute "result" could be:

% trying to exploit the column major ordering
Aprime = reshape(permute(A,[3,1,2]), [2,4]);
Bprime = reshape(permute(B,[3,1,2]), [2,4]);


>> Aprime
Aprime =

    1    4    2    5
   11   44   22   55

>> Bprime
Bprime =

    7    1    8    2
   77   11   88   22

Jetzt ersetzen wir die obige Schleife für Folgendes:

result= zeros(2,2);
....
temp = abs(Aprime - Bprime);
for k = 1:2
    result(i,j) = result(i,j) + temp(k, i+2*(j-1));
...

Wir haben die Daten neu angeordnet, um den Cache-Speicher nutzen zu können. Permutation und Umformung können kostspielig sein, aber wenn mit großen ND-Arrays gearbeitet wird, sind die mit diesen Vorgängen verbundenen Rechenkosten viel niedriger als mit nicht angeordneten Arrays.

Die Bedeutung der Vorbelegung

Arrays in MATLAB werden als fortlaufende Blöcke im Speicher gehalten, die von MATLAB automatisch zugewiesen und freigegeben werden. MATLAB verbirgt Speicherverwaltungsvorgänge wie die Größenänderung eines Arrays hinter einer einfach zu verwendenden Syntax:

a = 1:4

a =

     1     2     3     4

a(5) = 10  % or alternatively a = [a, 10]

a =

     1     2     3     4    10

Es ist wichtig zu verstehen, dass das Obige keine triviale Operation ist. a(5) = 10 bewirkt, dass MATLAB einen neuen Speicherblock der Größe 5 belegt, die ersten 4 Zahlen kopiert und den 5'ten Wert auf 10 setzt. Das ist eine O(numel(a)) und nicht O(1) .

Folgendes berücksichtigen:

clear all
n=12345678;
a=0;
tic
for i = 2:n
    a(i) = sqrt(a(i-1)) + i;
end
toc

Elapsed time is 3.004213 seconds.

a wird in dieser Schleife n mal neu zugewiesen (mit Ausnahme einiger von MATLAB durchgeführter Optimierungen)! Beachten Sie, dass MATLAB uns eine Warnung gibt:

"Die Variable 'a' scheint bei jeder Schleifeniteration die Größe zu ändern. Erwägen Sie eine Vorbelegung für die Geschwindigkeit."

Was passiert, wenn wir vorbelegen?

a=zeros(1,n);
tic
for i = 2:n
    a(i) = sqrt(a(i-1)) + i;
end
toc

Elapsed time is 0.410531 seconds.

Wir können sehen, dass sich die Laufzeit um eine Größenordnung verringert.

Methoden für die Vorbelegung:

MATLAB bietet verschiedene Funktionen zur Zuordnung von Vektoren und Matrizen, abhängig von den spezifischen Anforderungen des Benutzers. Dazu gehören: zeros , ones , nan , eye , true usw.

a = zeros(3)       % Allocates a 3-by-3 matrix initialized to 0
a =

     0     0     0
     0     0     0
     0     0     0

a = zeros(3, 2)     % Allocates a 3-by-2 matrix initialized to 0
a =

     0     0
     0     0
     0     0

a = ones(2, 3, 2)      % Allocates a 3 dimensional array (2-by-3-by-2) initialized to 1
a(:,:,1) =

     1     1     1
     1     1     1


a(:,:,2) =

     1     1     1
     1     1     1

a = ones(1, 3) * 7  % Allocates a row vector of length 3 initialized to 7
a =

     7     7     7

Ein Datentyp kann auch angegeben werden:

a = zeros(2, 1, 'uint8');  % allocates an array of type uint8

Es ist auch einfach, die Größe eines vorhandenen Arrays zu klonen:

a = ones(3, 4);       % a is a 3-by-4 matrix of 1's
b = zeros(size(a));  % b is a 3-by-4 matrix of 0's

Und klonen Sie den Typ:

a = ones(3, 4, 'single');       % a is a 3-by-4 matrix of type single
b = zeros(2, 'like', a);        % b is a 2-by-2 matrix of type single

Beachten Sie, dass „ Gefällt mir “ auch Komplexität und Sparsamkeit klont .

Die Vorabzuordnung wird implizit mithilfe einer Funktion erreicht, die ein Array mit der endgültigen erforderlichen Größe zurückgibt, z. B. rand , gallery , kron , bsxfun , colon und viele andere. Eine übliche Methode zum Zuweisen von Vektoren mit linear variierenden Elementen ist beispielsweise die Verwendung des Doppelpunktoperators (entweder mit der 2- oder 3-Operandenvariante 1 ):

a = 1:3 
a =

     1     2     3

a = 2:-3:-4
a =

     2    -1    -4

Zellen-Arrays können mit der Funktion cell() auf die gleiche Weise wie zeros() zugewiesen werden.

a = cell(2,3)
a = 

    []    []    []
    []    []    []

Beachten Sie, dass Zellenarrays funktionieren, indem sie Zeiger auf die Speicherstellen des Zelleninhalts halten. Daher gelten alle Vorbelegungstipps auch für die einzelnen Zellenarrayelemente.


Lesen Sie weiter:



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow