C’t Magazine

Programma's starten met Python ipv Bash

Met Python- in plaats van Bash-scripts programma's starten en resultaten verwerken

- Pina Merkert

Vanuit Python kun je ook zonder al teveel moeite programma's starten die in andere talen geschreven zijn. Python-programma's hebben voor typische programmee­rtaken echter wezenlijk minder code nodig dan Bash-scripts. Daarom is Python met zijn elegantere code prima geschikt om Bash te vervangen.

Voor het testen van een nieuwe grafische kaart gebruiken we onder meer de machine-learningbe­nchmark DeepBench. Die in C geprogramm­eerde benchmark bestaat uit drie afzonderli­jke tests die elk twee parameters accepteren en een hele batterij aan tijdmeting­en opleveren, bijvoorbee­ld voor matrixverm­enigvuldig­ingen met matrices van verschille­nde grootte. Om onzuivere resultaten door er toevallig tussendoor glippende systeempro­cessen te vermijden, voeren we elke benchmark drie keer uit en gebruiken we daar telkens het beste resultaat van. Van die resultaten berekenen we het meetkundig gemiddelde om tot één enkele waarde per test te komen. Dat levert een totaalresu­ltaat voor de performanc­e van een grafische kaart bij dit type berekening­en. Je kunt de benodigde 45 tests handmatig starten, de resultaten in Excel zetten en daar het resultaat mee berekenen, maar de testcomput­er kan dat automatisc­h helemaal zelf doen met een Python-script. Dit voorbeeld laat zien hoe makkelijk Python Bash-scripts en Bashbestan­den kan vervangen.

Een Bash-script zou de 45 afzonderli­jke tests met een paar loops relatief makkelijk kunnen starten. Bij het verwerken van de resultaten moet je dan wel wat magische sed-commando's bedenken om uit de console-uitvoer van de benchmarks de juiste getallen eruit te pikken. Bij het berekenen van het meetkundig gemiddelde zou je dan willen dat je een bibliothee­k als NumPy zou hebben, maar die is er voor Bash niet in zo'n handige vorm.

Python kan de scripts met net zo weinig code uitvoeren als een Bash-script, maar dan met behulp van reguliere expressies ook de resultaten er relatief makkelijk uit extraheren. Dat is mogelijk door de modules subprocess, re en numpy. De eerste kan willekeuri­ge programma's als eigen proces starten. De andere extraheren en verwerken de data.

Met subprocess.Popen() start je programma's vanuit Python die je ook via de console kunt starten. Het commando verwacht als parameter een lijst met als eerste item de naam van het programma en daarna de daarvoor benodigde parameters. Het starten van ../DeepBench/code/bin/ conv_bench train float wordt dan prc = subprocess.Popen([ "../DeepBench/code/bin/conv_bench", "train", "float"])

Als je Popen() dan nog de parameter stdout=subprocess.PIPE meegeeft, stuurt het programma zijn uitvoer door via een pipe. Die kun je met communicat­e() benaderen:

out = prc.communicat­e()[0]

In out staat dan alle uitvoer die het gestarte programma normaal gesproken naar de console geschreven zou hebben.

Resultaten verwerken

DeepBench voert de resultaten uit als een soort tabel die geformatte­erd is met spaties. Dat is een formaat dat in principe niet handig is om verder te verwerken, maar de uitvoer ziet er in elk geval altijd hetzelfde uit. Daarom kun je de resultaten filteren met reguliere expressies. De Python-module re

doet dat. Onze reguliere expressie verwacht gehele getallen \d+ die gescheiden zijn door minstens één spatie \s+. Omdat we de getallen verder willen bewerken, maken we een capturing-group aan door de getallen tussen ronde haakjes te zetten (\d+). Met re.compile() maak je van de string een reguliere-expressie-object. Als je daar de methode match() mee uitvoert, en je er telkens één regel van de benchmark-uitvoer aan meegeeft, ontstaat hierbij een Match-object. Aan de door de reguliere expressie gedefiniee­rde groepen (de delen van het commando die tussen ronde haakjes staan) kun je komen met behulp van match.groups(). In een iets kortere vorm ziet de code daarvoor er als volgt uit:

res_line = re.compile(r"^\s*(\d+)\s+

d+)\s+(\w+)\s*$") for line in out.splitlines(): match = res_line.match(line) if match: p, fw_time, f_alg =

match.groups()

Matrixreke­nen

De daarna met behulp van re geëxtrahee­rde benchmarkr­esultaten worden simpelweg naar de lijst results geschreven. Elk item op de lijst bestaat op zijn beurt uit een lijst van drie waarden, namelijk het resultaat van de afzonderli­jke benchmarkt­ests. Van die lijst van lijsten maakt np.array(results) een matrix. Daar kan NumPy vervolgens makkelijk mee rekenen. Met min(axis=0) zoek je bijvoorbee­ld naar de kleinste waarde in elke kolom, zodat daar een vector bij ontstaat:

np.array(results).min(axis=0)

Daarna staan in die vector de tijden van de beste uit drie benchmarkr­uns voor elke afzonderli­jke test.

Maar we willen liever een enkele waarde als resultaat geven in plaats van een hele vector. Die waarde wordt dan berekend als het meetkundig gemiddelde van de resultaten van de afzonderli­jke tests, respectiev­elijk de coördinate­n van de vector. Een functie voor het berekenen van het meetkundig gemiddelde zit in de module scipy. stats onder de naam gmean. SciPy komt van dezelfde ontwikkela­ars als NumPy en bevat honderden functies voor wetenschap­pelijke berekening­en. Het berekenen van het totaalresu­ltaat past daardoor op één regel:

gmean(np.array(results).min(axis=0))

Niets meer met de hand

De voordelen van Python ten opzichte van Bash zijn dan ook het grootst als je niet alleen programma's start met subprocess.Popen(), maar bovendien de resultaten ervan verder wilt bewerken. De berekening­en kun je in Python met een stuk minder regels definiëren dan in de console.

Het complete voorbeeld voor het analyseren met DeepBench staat bij de link hieronder. Daar staan extra coderegels in om de verschille­nd geformatte­erde uitvoer van de afzonderli­jke tests telkens op de juiste manier te extraheren. Alle uitgangspu­nten achter de scripts heb je echter in dit artikel kunnen lezen. (nkr)

 ??  ?? DeepBench laat de talrijke tijdmeting­en zien als een opgemaakte tabel. Het Python-script verwerkt die data volledig automatisc­h.
DeepBench laat de talrijke tijdmeting­en zien als een opgemaakte tabel. Het Python-script verwerkt die data volledig automatisc­h.

Newspapers in Dutch

Newspapers from Netherlands