Felsökning av ParallelRunStep
GÄLLER FÖR:Python SDK azureml v1
I den här artikeln får du lära dig hur du felsöker när du får fel med klassen ParallelRunStep från Azure Machine Learning SDK.
Allmänna tips om hur du felsöker en pipeline finns i Felsöka maskininlärningspipelines.
Testa skript lokalt
ParallelRunStep körs som ett steg i ML-pipelines. Du kanske vill testa dina skript lokalt som ett första steg.
Krav för postskript
Postskriptet för en ParallelRunStep
måste innehålla en run()
funktion och innehåller eventuellt en init()
funktion:
init()
: Använd den här funktionen för eventuella kostsamma eller vanliga förberedelser för senare bearbetning. Använd den till exempel för att läsa in modellen i ett globalt objekt. Den här funktionen anropas bara en gång i början av processen.Anteckning
Om din
init
metod skapar en utdatakatalog anger du denparents=True
ochexist_ok=True
. Metodeninit
anropas från varje arbetsprocess på varje nod där jobbet körs.run(mini_batch)
: Funktionen körs för varjemini_batch
instans.mini_batch
:ParallelRunStep
anropar körningsmetoden och skickar antingen en lista eller pandasDataFrame
som ett argument till metoden. Varje post i mini_batch blir en filsökväg om indata är enFileDataset
eller ett PandasDataFrame
om indata är enTabularDataset
.response
: run()-metoden ska returnera en PandasDataFrame
eller en matris. För append_row output_action läggs dessa returnerade element till i den gemensamma utdatafilen. För summary_only ignoreras innehållet i elementen. För alla utdataåtgärder anger varje returnerat utdataelement en lyckad körning av indataelementet i mini-batchen för indata. Se till att tillräckligt med data ingår i körningsresultatet för att mappa indata för att köra utdataresultatet. Körningsutdata skrivs i utdatafilen och är inte garanterade i ordning. Du bör använda en nyckel i utdata för att mappa den till indata.Anteckning
Ett utdataelement förväntas för ett indataelement.
%%writefile digit_identification.py
# Snippets from a sample script.
# Refer to the accompanying digit_identification.py
# (https://github.com/Azure/MachineLearningNotebooks/tree/master/how-to-use-azureml/machine-learning-pipelines/parallel-run)
# for the implementation script.
import os
import numpy as np
import tensorflow as tf
from PIL import Image
from azureml.core import Model
def init():
global g_tf_sess
# Pull down the model from the workspace
model_path = Model.get_model_path("mnist")
# Construct a graph to execute
tf.reset_default_graph()
saver = tf.train.import_meta_graph(os.path.join(model_path, 'mnist-tf.model.meta'))
g_tf_sess = tf.Session()
saver.restore(g_tf_sess, os.path.join(model_path, 'mnist-tf.model'))
def run(mini_batch):
print(f'run method start: {__file__}, run({mini_batch})')
resultList = []
in_tensor = g_tf_sess.graph.get_tensor_by_name("network/X:0")
output = g_tf_sess.graph.get_tensor_by_name("network/output/MatMul:0")
for image in mini_batch:
# Prepare each image
data = Image.open(image)
np_im = np.array(data).reshape((1, 784))
# Perform inference
inference_result = output.eval(feed_dict={in_tensor: np_im}, session=g_tf_sess)
# Find the best probability, and add it to the result list
best_result = np.argmax(inference_result)
resultList.append("{}: {}".format(os.path.basename(image), best_result))
return resultList
Om du har en annan fil eller mapp i samma katalog som ditt slutsatsdragningsskript kan du referera till den genom att hitta den aktuella arbetskatalogen. Om du vill importera paketen kan du också lägga till paketmappen i sys.path
.
script_dir = os.path.realpath(os.path.join(__file__, '..',))
file_path = os.path.join(script_dir, "<file_name>")
packages_dir = os.path.join(file_path, '<your_package_folder>')
if packages_dir not in sys.path:
sys.path.append(packages_dir)
from <your_package> import <your_class>
Parametrar för ParallelRunConfig
ParallelRunConfig
är den viktigaste konfigurationen för ParallelRunStep
till exempel i Azure Machine Learning-pipelinen. Du använder det för att omsluta skriptet och konfigurera nödvändiga parametrar, inklusive alla följande poster:
entry_script
: Ett användarskript som en lokal filsökväg som ska köras parallellt på flera noder. Omsource_directory
finns använder du en relativ sökväg. Annars kan du använda alla sökvägar som är tillgängliga på datorn.mini_batch_size
: Storleken på mini-batchen som skickas till ett endarun()
anrop. (valfritt; standardvärdet är10
filer förFileDataset
och1MB
förTabularDataset
.)- För
FileDataset
är det antalet filer med ett minsta värde på1
. Du kan kombinera flera filer i en mini-batch. - För
TabularDataset
är det storleken på data. Exempelvärden är1024
,1024KB
,10MB
och1GB
. Det rekommenderade värdet är1MB
. Mini-batchen frånTabularDataset
kommer aldrig att korsa filgränserna. Om du till exempel har .csv filer med olika storlekar är den minsta filen 100 kB och den största är 10 MB. Om du angermini_batch_size = 1MB
behandlas filer med en storlek som är mindre än 1 MB som en mini-batch. Filer med en storlek som är större än 1 MB delas upp i flera minibatchar.Anteckning
TabularDatasets som backas upp av SQL kan inte partitioneras. TabularDatasets från en enda parkettfil och en radgrupp kan inte partitioneras.
- För
error_threshold
: Antalet postfel förTabularDataset
och filfel förFileDataset
som ska ignoreras under bearbetningen. Om felantalet för hela indata överskrider det här värdet avbryts jobbet. Feltröskeln är för hela indata och inte för enskilda mini-batch som skickasrun()
till metoden. Intervallet är[-1, int.max]
. Delen-1
anger att alla fel ignoreras under bearbetningen.output_action
: Ett av följande värden anger hur utdata ska ordnas:summary_only
: Användarskriptet lagrar utdata.ParallelRunStep
använder endast utdata för beräkningen av feltröskeln.append_row
: För alla indata skapas endast en fil i utdatamappen för att lägga till alla utdata avgränsade med rad.
append_row_file_name
: Om du vill anpassa utdatafilens namn för append_row output_action (valfritt; standardvärdet ärparallel_run_step.txt
).source_directory
: Sökvägar till mappar som innehåller alla filer som ska köras på beräkningsmålet (valfritt).compute_target
: EndastAmlCompute
stöds.node_count
: Antalet beräkningsnoder som ska användas för att köra användarskriptet.process_count_per_node
: Antalet arbetsprocesser per nod för att köra postskriptet parallellt. För en GPU-dator är standardvärdet 1. För en CPU-dator är standardvärdet antalet kärnor per nod. En arbetsprocess anroparrun()
upprepade gånger genom att skicka den mini-batch som den får. Det totala antalet arbetsprocesser i jobbet ärprocess_count_per_node * node_count
, som bestämmer det maximala antaletrun()
som ska köras parallellt.environment
: Python-miljödefinitionen. Du kan konfigurera den så att den använder en befintlig Python-miljö eller för att konfigurera en tillfällig miljö. Definitionen ansvarar också för att ange nödvändiga programberoenden (valfritt).logging_level
: Logga utförlighet. Värden i ökande verbositet är:WARNING
,INFO
ochDEBUG
. (valfritt; standardvärdet ärINFO
)run_invocation_timeout
: Tidsgränsenrun()
för metodanrop i sekunder. (valfritt; standardvärdet är60
)run_max_try
: Maximalt antalrun()
försök för en mini-batch. Arun()
misslyckas om ett undantag utlöses, eller om inget returneras närrun_invocation_timeout
har uppnåtts (valfritt; standardvärdet är3
).
Du kan ange mini_batch_size
, node_count
, process_count_per_node
, logging_level
, run_invocation_timeout
och run_max_try
som PipelineParameter
, så att du kan finjustera parametervärdena när du skickar en pipelinekörning igen. I det här exemplet använder PipelineParameter
du för mini_batch_size
och Process_count_per_node
och ändrar dessa värden när du skickar en ny körning.
SYNLIGHET FÖR CUDA-enheter
För beräkningsmål som är utrustade med GPU:er anges miljövariabeln CUDA_VISIBLE_DEVICES
i arbetsprocesser. I AmlCompute hittar du det totala antalet GPU-enheter i miljövariabeln AZ_BATCHAI_GPU_COUNT_FOUND
, som anges automatiskt. Om du vill att varje arbetsprocess ska ha en dedikerad GPU anger du process_count_per_node
lika med antalet GPU-enheter på en dator. Varje arbetsprocess tilldelar ett unikt index till CUDA_VISIBLE_DEVICES
. Om en arbetsprocess stoppas av någon anledning använder nästa påbörjade arbetsprocess det utgivna GPU-indexet.
Om det totala antalet GPU-enheter är mindre än process_count_per_node
tilldelas arbetsprocesserna GPU-index tills alla har använts.
Med tanke på att det totala antalet GPU-enheter är 2 och process_count_per_node = 4
som ett exempel har process 0 och process 1 index 0 och 1. Process 2 och 3 har ingen miljövariabel. För ett bibliotek som använder den här miljövariabeln för GPU-tilldelning har process 2 och 3 inte GPU:er och försöker inte hämta GPU-enheter. Om processen 0 stoppas släpper den GPU-index 0. Nästa process, som är process 4, har GPU-index 0 tilldelat.
Mer information finns i CUDA Pro Tips: Kontrollera GPU-synlighet med CUDA_VISIBLE_DEVICES.
Parametrar för att skapa ParallelRunStep
Skapa ParallelRunStep med hjälp av skript, miljökonfiguration och parametrar. Ange det beräkningsmål som du redan har kopplat till din arbetsyta som mål för körning för ditt slutsatsdragningsskript. Använd ParallelRunStep
för att skapa steget för batchinferenspipeline, som tar alla följande parametrar:
name
: Namnet på steget med följande namngivningsbegränsningar: unikt, 3–32 tecken och regex ^[a-z]([-a-z0-9]*[a-z0-9])?$.parallel_run_config
: EttParallelRunConfig
objekt som definierats tidigare.inputs
: En eller flera Azure Machine Learning-datauppsättningar som ska partitioneras för parallell bearbetning.side_inputs
: En eller flera referensdata eller datauppsättningar som används som sidoindata utan att behöva partitioneras.output
: EttOutputFileDatasetConfig
objekt som representerar katalogsökvägen där utdata ska lagras.arguments
: En lista med argument som skickas till användarskriptet. Använd unknown_args för att hämta dem i ditt postskript (valfritt).allow_reuse
: Om steget ska återanvända tidigare resultat när det körs med samma inställningar/indata. Om den här parametern ärFalse
genereras alltid en ny körning för det här steget under pipelinekörningen. (valfritt; standardvärdet ärTrue
.)
from azureml.pipeline.steps import ParallelRunStep
parallelrun_step = ParallelRunStep(
name="predict-digits-mnist",
parallel_run_config=parallel_run_config,
inputs=[input_mnist_ds_consumption],
output=output_dir,
allow_reuse=True
)
Felsöka skript från fjärrkontext
Övergången från att felsöka ett bedömningsskript lokalt till att felsöka ett bedömningsskript i en faktisk pipeline kan vara ett svårt steg. Information om hur du hittar loggarna i portalen finns i avsnittet om maskininlärningspipelines om felsökning av skript från en fjärrkontext. Informationen i det avsnittet gäller även för en ParallelRunStep.
Loggfilen 70_driver_log.txt
innehåller till exempel information från kontrollanten som startar ParallelRunStep-koden.
På grund av den distribuerade typen av ParallelRunStep-jobb finns det loggar från flera olika källor. Två konsoliderade filer skapas dock som ger information på hög nivå:
~/logs/job_progress_overview.txt
: Den här filen innehåller information på hög nivå om antalet minibatchar (även kallade uppgifter) som skapats hittills och antalet minibatchar som bearbetats hittills. I det här slutet visas resultatet av jobbet. Om jobbet misslyckades visas felmeddelandet och var felsökningen ska startas.~/logs/sys/master_role.txt
: Den här filen tillhandahåller huvudnoden (kallas även orchestrator) för det jobb som körs. Innehåller uppgiftsskapande, förloppsövervakning, körningsresultatet.
Loggar som genereras från postskript med hjälp av EntryScript-hjälpen och utskriftsinstruktioner finns i följande filer:
~/logs/user/entry_script_log/<node_id>/<process_name>.log.txt
: Dessa filer är loggarna som skrivits från entry_script med hjälp av EntryScript-hjälpen.~/logs/user/stdout/<node_id>/<process_name>.stdout.txt
: Dessa filer är loggarna från stdout (till exempel utskriftsinstruktor) för entry_script.~/logs/user/stderr/<node_id>/<process_name>.stderr.txt
: Dessa filer är loggarna från stderr för entry_script.
För en kortfattad förståelse av fel i skriptet finns det:
~/logs/user/error.txt
: Den här filen försöker sammanfatta felen i skriptet.
Mer information om fel i skriptet finns:
~/logs/user/error/
: Innehåller fullständiga stackspårningar av undantag som genereras vid inläsning och körning av postskript.
När du behöver en fullständig förståelse för hur varje nod körde poängskriptet kan du titta på de enskilda processloggarna för varje nod. Processloggarna finns i sys/node
mappen, grupperade efter arbetsnoder:
~/logs/sys/node/<node_id>/<process_name>.txt
: Den här filen innehåller detaljerad information om varje mini-batch när den hämtas eller slutförs av en arbetare. För varje mini-batch innehåller den här filen:- IP-adressen och PID för arbetsprocessen.
- Det totala antalet objekt, antalet bearbetade objekt och antalet misslyckade objekt.
- Starttid, varaktighet, processtid och körningsmetodtid.
Du kan också visa resultatet av regelbundna kontroller av resursanvändningen för varje nod. Loggfilerna och installationsfilerna finns i den här mappen:
~/logs/perf
: Ange--resource_monitor_interval
för att ändra kontrollintervallet i sekunder. Standardintervallet är600
, vilket är cirka 10 minuter. Om du vill stoppa övervakningen anger du värdet till0
. Varje<node_id>
mapp innehåller:os/
: Information om alla processer som körs i noden. En kontroll kör ett operativsystemkommando och sparar resultatet i en fil. I Linux ärps
kommandot . I Windows använder dutasklist
.%Y%m%d%H
: Undermappens namn är tid till timme.processes_%M
: Filen slutar med minut för kontrolltiden.
node_disk_usage.csv
: Detaljerad diskanvändning av noden.node_resource_usage.csv
: Översikt över resursanvändning för noden.processes_resource_usage.csv
: Översikt över resursanvändning för varje process.
Hur gör jag för att logg från mitt användarskript från en fjärrkontext?
ParallelRunStep kan köra flera processer på en nod baserat på process_count_per_node. För att organisera loggar från varje process på noden och kombinera utskrifts- och logguttryck rekommenderar vi att du använder ParallelRunStep-loggning enligt nedan. Du får en loggare från EntryScript och gör så att loggarna visas i loggar/användarmapp i portalen.
Ett exempelinmatningsskript med hjälp av loggern:
from azureml_user.parallel_run import EntryScript
def init():
"""Init once in a worker process."""
entry_script = EntryScript()
logger = entry_script.logger
logger.info("This will show up in files under logs/user on the Azure portal.")
def run(mini_batch):
"""Call once for a mini batch. Accept and return the list back."""
# This class is in singleton pattern and will return same instance as the one in init()
entry_script = EntryScript()
logger = entry_script.logger
logger.info(f"{__file__}: {mini_batch}.")
...
return mini_batch
Var sjunker meddelandet från Python logging
till?
ParallelRunStep ställer in en hanterare på rotloggaren, som sänker meddelandet till logs/user/stdout/<node_id>/processNNN.stdout.txt
.
logging
standardvärdet är nivå INFO
. Som standard visas inte nivåerna nedan INFO
, till exempel DEBUG
.
Hur kan jag skriva till en fil för att visas i portalen?
Filer i logs
mappen laddas upp och visas i portalen.
Du kan hämta mappen logs/user/entry_script_log/<node_id>
som nedan och skriva din filsökväg för att skriva:
from pathlib import Path
from azureml_user.parallel_run import EntryScript
def init():
"""Init once in a worker process."""
entry_script = EntryScript()
log_dir = entry_script.log_dir
log_dir = Path(entry_script.log_dir) # logs/user/entry_script_log/<node_id>/.
log_dir.mkdir(parents=True, exist_ok=True) # Create the folder if not existing.
proc_name = entry_script.agent_name # The process name in pattern "processNNN".
fil_path = log_dir / f"{proc_name}_<file_name>" # Avoid conflicting among worker processes with proc_name.
Hur hanterar jag inloggning i nya processer?
Du kan skapa nya processer i ditt postskript med subprocess
modulen, ansluta till deras indata-/utdata-/felpipor och hämta deras returkoder.
Den rekommenderade metoden är att använda run()
funktionen med capture_output=True
. Fel visas i logs/user/error/<node_id>/<process_name>.txt
.
Om du vill använda Popen()
bör du omdirigera stdout/stderr till filer, till exempel:
from pathlib import Path
from subprocess import Popen
from azureml_user.parallel_run import EntryScript
def init():
"""Show how to redirect stdout/stderr to files in logs/user/entry_script_log/<node_id>/."""
entry_script = EntryScript()
proc_name = entry_script.agent_name # The process name in pattern "processNNN".
log_dir = Path(entry_script.log_dir) # logs/user/entry_script_log/<node_id>/.
log_dir.mkdir(parents=True, exist_ok=True) # Create the folder if not existing.
stdout_file = str(log_dir / f"{proc_name}_demo_stdout.txt")
stderr_file = str(log_dir / f"{proc_name}_demo_stderr.txt")
proc = Popen(
["...")],
stdout=open(stdout_file, "w"),
stderr=open(stderr_file, "w"),
# ...
)
Anteckning
En arbetsprocess kör "systemkod" och postskriptkoden i samma process.
Om inget stdout
eller stderr
anges ärver en underprocess som skapats med Popen()
i ditt postskript inställningen för arbetsprocessen.
stdout
skriver till logs/sys/node/<node_id>/processNNN.stdout.txt
och stderr
till logs/sys/node/<node_id>/processNNN.stderr.txt
.
Hur gör jag för att skriva en fil till utdatakatalogen och sedan visa den i portalen?
Du kan hämta utdatakatalogen EntryScript
från klassen och skriva till den. Om du vill visa de skrivna filerna går du till steget Kör i Azure Machine Learning-portalen och väljer fliken Utdata + loggar . Välj länken Datautdata och slutför sedan stegen som beskrivs i dialogrutan.
Använd EntryScript
i ditt postskript som i det här exemplet:
from pathlib import Path
from azureml_user.parallel_run import EntryScript
def run(mini_batch):
output_dir = Path(entry_script.output_dir)
(Path(output_dir) / res1).write...
(Path(output_dir) / res2).write...
Hur skickar jag indata på sidan, till exempel en fil eller fil som innehåller en uppslagstabell, till alla mina arbetare?
Användaren kan skicka referensdata till skript med hjälp av side_inputs parametern ParalleRunStep. Alla datauppsättningar som tillhandahålls som side_inputs monteras på varje arbetsnod. Användaren kan hämta monteringsplatsen genom att skicka argument.
Skapa en datauppsättning som innehåller referensdata, ange en lokal monteringssökväg och registrera den med din arbetsyta. Skicka den till parametern side_inputs
för din ParallelRunStep
. Dessutom kan du lägga till sökvägen i arguments
avsnittet för att enkelt komma åt den monterade sökvägen.
Anteckning
Använd endast FileDatasets för side_inputs.
local_path = "/tmp/{}".format(str(uuid.uuid4()))
label_config = label_ds.as_named_input("labels_input").as_mount(local_path)
batch_score_step = ParallelRunStep(
name=parallel_step_name,
inputs=[input_images.as_named_input("input_images")],
output=output_dir,
arguments=["--labels_dir", label_config],
side_inputs=[label_config],
parallel_run_config=parallel_run_config,
)
Därefter kan du komma åt det i ditt slutsatsdragningsskript (till exempel i din init()-metod) på följande sätt:
parser = argparse.ArgumentParser()
parser.add_argument('--labels_dir', dest="labels_dir", required=True)
args, _ = parser.parse_known_args()
labels_path = args.labels_dir
Hur använder du indatauppsättningar med autentisering med tjänstens huvudnamn?
Användaren kan skicka indatauppsättningar med autentisering med tjänstens huvudnamn som används på arbetsytan. Om du använder en sådan datauppsättning i ParallelRunStep måste datauppsättningen registreras för att den ska kunna konstruera ParallelRunStep-konfigurationen.
service_principal = ServicePrincipalAuthentication(
tenant_id="***",
service_principal_id="***",
service_principal_password="***")
ws = Workspace(
subscription_id="***",
resource_group="***",
workspace_name="***",
auth=service_principal
)
default_blob_store = ws.get_default_datastore() # or Datastore(ws, '***datastore-name***')
ds = Dataset.File.from_files(default_blob_store, '**path***')
registered_ds = ds.register(ws, '***dataset-name***', create_new_version=True)
Så här kontrollerar du förloppet och analyserar det
Det här avsnittet handlar om hur du kontrollerar förloppet för ett ParallelRunStep-jobb och kontrollerar orsaken till ett oväntat beteende.
Så här kontrollerar du jobbets förlopp?
Förutom att titta på den övergripande statusen för StepRun kan antalet schemalagda/bearbetade minibatchar och förloppet för att generera utdata visas i ~/logs/job_progress_overview.<timestamp>.txt
. Filen roterar dagligen. Du kan kontrollera den med den största tidsstämpeln för den senaste informationen.
Vad ska jag kontrollera om det inte finns några framsteg på ett tag?
Du kan gå in ~/logs/sys/errror
för att se om det finns något undantag. Om det inte finns något, är det troligt att ditt postskript tar lång tid, du kan skriva ut förloppsinformation i koden för att hitta den tidskrävande delen eller lägga till "--profiling_module", "cProfile"
i arguments
för ParallelRunStep
att generera en profilfil med namnet under <process_name>.profile
~/logs/sys/node/<node_id>
mappen.
När stoppas ett jobb?
om det inte avbryts stoppas jobbet med status:
- Avslutade. Om alla mini-batchar har bearbetats och utdata har genererats för
append_row
läge. - Misslyckades. Om
error_threshold
inParameters for ParallelRunConfig
överskrids eller om systemfel uppstod under jobbet.
Var hittar du rotorsaken till felet?
Du kan följa leadet i ~logs/job_result.txt
för att hitta orsaksloggen och den detaljerade felloggen.
Påverkar nodfel jobbresultatet?
Inte om det finns andra tillgängliga noder i det avsedda beräkningsklustret. Orkestreraren startar en ny nod som ersättning och ParallelRunStep är motståndskraftig mot den här åtgärden.
Vad händer om init
funktionen i inmatningsskriptet misslyckas?
ParallelRunStep har en mekanism för att försöka igen under en viss tid för att ge möjlighet till återställning från tillfälliga problem utan att fördröja jobbfelet för länge. Mekanismen är följande:
- Om alla agenter misslyckas när en nod startar
init
slutar vi att försöka efter3 * process_count_per_node
fel. - Om alla agenter för alla noder misslyckas när jobbet startar
init
slutar vi att försöka om jobbet körs mer än 2 minuter och det uppstår2 * node_count * process_count_per_node
fel. - Om alla agenter har fastnat i
init
mer än3 * run_invocation_timeout + 30
sekunder misslyckas jobbet på grund av att inga förlopp har för lång tid.
Vad kommer att hända på OutOfMemory? Hur kontrollerar jag orsaken?
ParallelRunStep anger det aktuella försöket att bearbeta mini-batchen till felstatus och försöker starta om den misslyckade processen. Du kan söka efter ~logs/perf/<node_id>
den minneskrävande processen.
Varför har jag många processNNN-filer?
ParallelRunStep startar nya arbetsprocesser i stället för de som avslutas onormalt, och varje process genererar en processNNN
fil som logg. Men om processen misslyckades på grund av ett undantag under init
funktionen för användarskriptet och felet upprepas kontinuerligt under 3 * process_count_per_node
tider, kommer ingen ny arbetsprocess att startas.
Nästa steg
Se de här Jupyter-notebook-filerna som demonstrerar Azure Machine Learning-pipelines
Se SDK-referensen för hjälp med paketet azureml-pipeline-steps .
Visa referensdokumentation för klassen ParallelRunConfig och dokumentationen för klassen ParallelRunStep.
Följ den avancerade självstudien om hur du använder pipelines med ParallelRunStep. Självstudien visar hur du skickar en annan fil som en sidoinmatning.