Zoeken…


Opmerkingen

  • Profilering code is een manier om de gevreesde praktijk van "het voorkomen voortijdige optimalisatie ", door zich te richten de ontwikkelaar op die delen van de code die daadwerkelijk optimalisatie inspanningen te rechtvaardigen.
  • MATLAB-documentatieartikel getiteld " Prestaties van uw programma meten ".

Knelpunten in de prestaties identificeren met de Profiler

De MATLAB Profiler is een hulpmiddel voor softwareprofilering van MATLAB-code. Met behulp van de Profiler is het mogelijk om een visuele weergave te krijgen van zowel de uitvoeringstijd als het geheugenverbruik.

Het uitvoeren van de Profiler kan op twee manieren:

  • Klik op de knop "Uitvoeren en tijd" in de MATLAB GUI terwijl er een .m bestand geopend is in de editor (toegevoegd in R2012b ).

    Knop in toolstrip

  • Programmatisch met behulp van:

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

Hieronder vindt u enkele voorbeeldcode en het resultaat van de profilering:

function docTest

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

spy

Profiler-uitgang

Uit het bovenstaande leren we dat de spy ongeveer 25% van de totale uitvoeringstijd in beslag neemt. In het geval van "echte code" zou een functie die zo'n groot percentage van de uitvoeringstijd in beslag neemt een goede kandidaat zijn voor optimalisatie, in tegenstelling tot functies analoog aan var en cla waarvan de optimalisatie moet worden vermeden.

Bovendien is het mogelijk om op items in de kolom Functienaam te klikken om een gedetailleerd overzicht van de uitvoeringstijd voor dat item te zien. Hier is het voorbeeld van klikken op spy :

Interne timing van "spion"


Het is ook mogelijk om geheugenconsumptie te profileren door profile('-memory') voordat de Profiler wordt uitgevoerd.

voer hier de afbeeldingsbeschrijving in

Vergelijking van de uitvoeringstijd van meerdere functies

De veel gebruikte combinatie van tic en toc kan een ruw idee geven van de uitvoeringstijd van een functie of codefragmenten.

Voor het vergelijken van verschillende functies moet het niet worden gebruikt. Waarom? Het is bijna onmogelijk om alle codefragmenten gelijke voorwaarden te bieden om in een script met bovenstaande oplossing te vergelijken. Misschien delen de functies dezelfde functieruimte en gemeenschappelijke variabelen, zodat later genoemde functies en codefragmenten al profiteren van eerder geïnitialiseerde variabelen en functies. Ook is er geen inzicht of de JIT-compiler deze vervolgens genoemde fragmenten gelijk zou behandelen.


De speciale functie voor benchmarks is timeit . Het volgende voorbeeld illustreert het gebruik ervan.

Er zijn de array A en de matrix B Bepaald moet worden welke rij van B het meest op A lijkt door het aantal verschillende elementen te tellen.

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

Deze manier van benchmark werd voor het eerst in dit antwoord gezien .

Het is ok om `single 'te zijn!

Overzicht:

Het standaard gegevenstype voor numerieke arrays in MATLAB is double . double is een weergave van getallen met drijvende komma en dit formaat neemt 8 bytes (of 64 bits) per waarde in beslag. In sommige gevallen, waar bijvoorbeeld alleen het omgaan met gehele getallen of wanneer numerieke instabiliteit geen dreigend probleem is, is een dergelijke hoge bitdiepte mogelijk niet vereist. Om deze reden wordt geadviseerd om de voordelen van single precisie (of andere geschikte typen ) te overwegen:

  • Snellere uitvoeringstijd (vooral merkbaar op GPU's).
  • De helft van het geheugenverbruik: kan slagen wanneer double mislukt vanwege een geheugenfout; compacter bij het opslaan als bestanden.

Het omzetten van een variabele van elk ondersteund gegevenstype naar single gebeurt met behulp van:

sing_var = single(var);

Sommige veelgebruikte functies (zoals: zeros , eye , ones , etc. ) die standaard double waarden uitvoeren, maken het mogelijk om het type / de klasse van de uitvoer op te geven.

Variabelen in een script omzetten naar een niet-standaard precisie / type / klasse:

Vanaf juli 2016 bestaat er geen gedocumenteerde manier om het standaard MATLAB-gegevenstype te wijzigen van double .

In MATLAB bootsen nieuwe variabelen meestal de gegevenstypen van variabelen na die worden gebruikt bij het maken ervan. Om dit te illustreren, overweeg het volgende voorbeeld:

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  

Het kan dus voldoende lijken om verschillende initiële variabelen te casten / converteren om de verandering door de code te laten doordringen - dit wordt echter afgeraden (zie kanttekeningen en valkuilen hieronder).

Voorbehoud & valkuilen:

  1. Herhaalde conversies worden afgeraden vanwege de introductie van numerieke ruis (bij het casten van single naar double ) of verlies van informatie (bij het casten van double naar single of tussen bepaalde typen gehele getallen ), bijvoorbeeld:

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

    Dit kan enigszins worden beperkt met typecast . Zie ook Let op drijvende komma onnauwkeurigheid .

  2. Het uitsluitend ontmoedigen van impliciet typen van gegevens (dat wil zeggen wat MATLAB denkt dat het type uitvoer van een berekening zou moeten zijn) wordt afgeraden vanwege verschillende ongewenste effecten die kunnen optreden:

    • Verlies van informatie : wanneer een double resultaat wordt verwacht, maar een achteloze combinatie van single en double operanden levert single precisie op.

    • Onverwacht hoog geheugenverbruik : wanneer een single resultaat wordt verwacht, maar een onzorgvuldige berekening resulteert in een double uitvoer.

    • Onnodige overhead bij het werken met GPU's : bij het mengen van gpuArray typen (dwz variabelen die zijn opgeslagen in VRAM) met niet- gpuArray variabelen (dwz die meestal worden opgeslagen in RAM) moeten de gegevens op de een of andere manier worden overgedragen voordat de berekening kan worden uitgevoerd. Deze bewerking kost tijd en kan zeer merkbaar zijn in repetitieve berekeningen.

    • Fouten bij het mengen van drijvende-komma-typen met gehele getallen : functies zoals mtimes ( * ) zijn niet gedefinieerd voor gemengde invoer van gehele en drijvende komma-typen - en zullen fouten bevatten. Functies zoals times ( .* ) Zijn helemaal niet gedefinieerd voor invoer van het gehele type - en zullen opnieuw fouten maken.

      >> 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.
      

    Voor een betere leesbaarheid van de code en een verminderd risico op ongewenste typen, wordt een defensieve aanpak geadviseerd , waarbij variabelen expliciet naar het gewenste type worden gegoten.


Zie ook:

een ND-array herschikken kan de algehele prestaties verbeteren

In sommige gevallen moeten we functies toepassen op een set ND-arrays. Laten we dit eenvoudige voorbeeld bekijken.

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 matrices zijn 3D, laten we zeggen dat we het volgende moeten berekenen:

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

Nu vervangen we de bovenstaande lus als volgt:

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

We hebben de gegevens opnieuw ingedeeld zodat we het cachegeheugen kunnen benutten. Permutatie en hervorming kunnen kostbaar zijn, maar bij het werken met grote ND-arrays zijn de rekenkosten voor deze bewerkingen veel lager dan bij het werken met niet-gearrangeerde arrays.

Het belang van preallocatie

Arrays in MATLAB worden als continue blokken in het geheugen bewaard, toegewezen en automatisch vrijgegeven door MATLAB. MATLAB verbergt geheugenbeheerbewerkingen zoals het wijzigen van het formaat van een array achter eenvoudig te gebruiken syntaxis:

a = 1:4

a =

     1     2     3     4

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

a =

     1     2     3     4    10

Het is belangrijk om te begrijpen dat het bovenstaande geen triviale bewerking is, a(5) = 10 zorgt ervoor dat MATLAB een nieuw geheugenblok van grootte 5 toewijst, de eerste 4 nummers kopieert en de 5e op 10 zet. Dat is een O(numel(a)) bewerking en geen O(1) .

Stel je de volgende situatie voor:

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 wordt n keer opnieuw toegewezen in deze lus (exclusief enkele optimalisaties uitgevoerd door MATLAB)! Merk op dat MATLAB ons een waarschuwing geeft:

"De variabele 'a' lijkt van grootte te veranderen bij elke lus-iteratie. Overweeg voorallocatie voor snelheid."

Wat gebeurt er als we vooraf toewijzen?

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

Elapsed time is 0.410531 seconds.

We kunnen zien dat de looptijd wordt verlaagd met een orde van grootte.

Methoden voor preallocatie:

MATLAB biedt verschillende functies voor het toewijzen van vectoren en matrices, afhankelijk van de specifieke vereisten van de gebruiker. Deze omvatten: zeros , ones , nan , eye , true etc.

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

Een gegevenstype kan ook worden gespecificeerd:

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

Het is ook eenvoudig om de grootte van een bestaande array te 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

En kloon het type:

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

merk op dat 'like' ook complexiteit en spaarzaamheid kloneert .

Preallocatie wordt impliciet bereikt met behulp van elke functie die een array van de uiteindelijke vereiste grootte retourneert, zoals rand , gallery , kron , bsxfun , colon en vele anderen. Een veelgebruikte manier om vectoren toe te wijzen met lineair variërende elementen is bijvoorbeeld met de dubbele punt-operator (met de 2- of 3-operandvariant 1 ):

a = 1:3 
a =

     1     2     3

a = 2:-3:-4
a =

     2    -1    -4

Celmatrices kunnen worden toegewezen met behulp van de functie cell() op vrijwel dezelfde manier als zeros() .

a = cell(2,3)
a = 

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

Merk op dat celmatrices werken door wijzers naar de locaties in het geheugen van celinhoud te houden. Dus alle preallocatietips zijn ook van toepassing op de afzonderlijke celarray-elementen.


Verder lezen:



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow