[docs]classBasicTimeProfiler:""" BasicTimeProfiler can be used to profile the handlers, events, data loading and data processing times. Examples: .. code-block:: python from ignite.contrib.handlers import BasicTimeProfiler trainer = Engine(train_updater) # Create an object of the profiler and attach an engine to it profiler = BasicTimeProfiler() profiler.attach(trainer) @trainer.on(Events.EPOCH_COMPLETED) def log_intermediate_results(): profiler.print_results(profiler.get_results()) trainer.run(dataloader, max_epochs=3) profiler.write_results('path_to_dir/time_profiling.csv') """events_to_ignore=[Events.EXCEPTION_RAISED,Events.TERMINATE,Events.TERMINATE_SINGLE_EPOCH,Events.DATALOADER_STOP_ITERATION,]def__init__(self):self._dataflow_timer=Timer()self._processing_timer=Timer()self._event_handlers_timer=Timer()self.dataflow_times=Noneself.processing_times=Noneself.event_handlers_times=Noneself._events=[Events.EPOCH_STARTED,Events.EPOCH_COMPLETED,Events.ITERATION_STARTED,Events.ITERATION_COMPLETED,Events.GET_BATCH_STARTED,Events.GET_BATCH_COMPLETED,Events.COMPLETED,]self._fmethods=[self._as_first_epoch_started,self._as_first_epoch_completed,self._as_first_iter_started,self._as_first_iter_completed,self._as_first_get_batch_started,self._as_first_get_batch_completed,self._as_first_completed,]self._lmethods=[self._as_last_epoch_started,self._as_last_epoch_completed,self._as_last_iter_started,self._as_last_iter_completed,self._as_last_get_batch_started,self._as_last_get_batch_completed,self._as_last_completed,]def_reset(self,num_epochs,total_num_iters):self.dataflow_times=torch.zeros(total_num_iters)self.processing_times=torch.zeros(total_num_iters)self.event_handlers_times={Events.STARTED:torch.zeros(1),Events.COMPLETED:torch.zeros(1),Events.EPOCH_STARTED:torch.zeros(num_epochs),Events.EPOCH_COMPLETED:torch.zeros(num_epochs),Events.ITERATION_STARTED:torch.zeros(total_num_iters),Events.ITERATION_COMPLETED:torch.zeros(total_num_iters),Events.GET_BATCH_COMPLETED:torch.zeros(total_num_iters),Events.GET_BATCH_STARTED:torch.zeros(total_num_iters),}def_as_first_started(self,engine):ifhasattr(engine.state.dataloader,"__len__"):num_iters_per_epoch=len(engine.state.dataloader)else:num_iters_per_epoch=engine.state.epoch_lengthself.max_epochs=engine.state.max_epochsself.total_num_iters=self.max_epochs*num_iters_per_epochself._reset(self.max_epochs,self.total_num_iters)self.event_handlers_names={e:[h.__qualname__ifhasattr(h,"__qualname__")elseh.__class__.__name__for(h,_,_)inengine._event_handlers[e]if"BasicTimeProfiler."notinrepr(h)# avoid adding internal handlers into output]foreinEventsifenotinself.events_to_ignore}# Setup all other handlers:engine._event_handlers[Events.STARTED].append((self._as_last_started,(engine,),{}))fore,minzip(self._events,self._fmethods):engine._event_handlers[e].insert(0,(m,(engine,),{}))fore,minzip(self._events,self._lmethods):engine._event_handlers[e].append((m,(engine,),{}))# Let's goself._event_handlers_timer.reset()def_as_last_started(self,engine):self.event_handlers_times[Events.STARTED][0]=self._event_handlers_timer.value()def_as_first_epoch_started(self,engine):self._event_handlers_timer.reset()def_as_last_epoch_started(self,engine):t=self._event_handlers_timer.value()e=engine.state.epoch-1self.event_handlers_times[Events.EPOCH_STARTED][e]=tdef_as_first_get_batch_started(self,engine):self._event_handlers_timer.reset()self._dataflow_timer.reset()def_as_last_get_batch_started(self,engine):t=self._event_handlers_timer.value()i=engine.state.iteration-1self.event_handlers_times[Events.GET_BATCH_STARTED][i]=tdef_as_first_get_batch_completed(self,engine):self._event_handlers_timer.reset()def_as_last_get_batch_completed(self,engine):t=self._event_handlers_timer.value()i=engine.state.iteration-1self.event_handlers_times[Events.GET_BATCH_COMPLETED][i]=td=self._dataflow_timer.value()self.dataflow_times[i]=dself._dataflow_timer.reset()def_as_first_iter_started(self,engine):self._event_handlers_timer.reset()def_as_last_iter_started(self,engine):t=self._event_handlers_timer.value()i=engine.state.iteration-1self.event_handlers_times[Events.ITERATION_STARTED][i]=tself._processing_timer.reset()def_as_first_iter_completed(self,engine):t=self._processing_timer.value()i=engine.state.iteration-1self.processing_times[i]=tself._event_handlers_timer.reset()def_as_last_iter_completed(self,engine):t=self._event_handlers_timer.value()i=engine.state.iteration-1self.event_handlers_times[Events.ITERATION_COMPLETED][i]=tdef_as_first_epoch_completed(self,engine):self._event_handlers_timer.reset()def_as_last_epoch_completed(self,engine):t=self._event_handlers_timer.value()e=engine.state.epoch-1self.event_handlers_times[Events.EPOCH_COMPLETED][e]=tdef_as_first_completed(self,engine):self._event_handlers_timer.reset()def_as_last_completed(self,engine):self.event_handlers_times[Events.COMPLETED][0]=self._event_handlers_timer.value()# Remove added handlers:engine.remove_event_handler(self._as_last_started,Events.STARTED)fore,minzip(self._events,self._fmethods):engine.remove_event_handler(m,e)fore,minzip(self._events,self._lmethods):engine.remove_event_handler(m,e)defattach(self,engine):ifnotisinstance(engine,Engine):raiseTypeError("Argument engine should be ignite.engine.Engine, ""but given {}".format(type(engine)))ifnotengine.has_event_handler(self._as_first_started):engine._event_handlers[Events.STARTED].insert(0,(self._as_first_started,(engine,),{}))@staticmethoddef_compute_basic_stats(data):# compute on non-zero data:data=data[data>0]out=[("total",torch.sum(data).item()iflen(data)>0else"not yet triggered")]iflen(data)>1:out+=[("min/index",(torch.min(data).item(),torch.argmin(data).item())),("max/index",(torch.max(data).item(),torch.argmax(data).item())),("mean",torch.mean(data).item()),("std",torch.std(data).item()),]returnOrderedDict(out)
[docs]defget_results(self):""" Method to fetch the aggregated profiler results after the engine is run .. code-block:: python results = profiler.get_results() """total_eh_time=sum([(self.event_handlers_times[e]).sum()foreinEventsifenotinself.events_to_ignore])returnOrderedDict([("processing_stats",self._compute_basic_stats(self.processing_times)),("dataflow_stats",self._compute_basic_stats(self.dataflow_times)),("event_handlers_stats",dict([(str(e.name).replace(".","_"),self._compute_basic_stats(self.event_handlers_times[e]))foreinEventsifenotinself.events_to_ignore]+[("total_time",total_eh_time)]),),("event_handlers_names",{str(e.name).replace(".","_")+"_names":vfore,vinself.event_handlers_names.items()},),])
[docs]defwrite_results(self,output_path):""" Method to store the unaggregated profiling results to a csv file .. code-block:: python profiler.write_results('path_to_dir/awesome_filename.csv') Example output: .. code-block:: text ----------------------------------------------------------------- epoch iteration processing_stats dataflow_stats Event_STARTED ... 1.0 1.0 0.00003 0.252387 0.125676 1.0 2.0 0.00029 0.252342 0.125123 """try:importpandasaspdexceptImportError:print("Need pandas to write results as files")returniters_per_epoch=self.total_num_iters//self.max_epochsepochs=torch.arange(self.max_epochs,dtype=torch.float32).repeat_interleave(iters_per_epoch)+1iterations=torch.arange(self.total_num_iters,dtype=torch.float32)+1processing_stats=self.processing_timesdataflow_stats=self.dataflow_timesevent_started=self.event_handlers_times[Events.STARTED].repeat_interleave(self.total_num_iters)event_completed=self.event_handlers_times[Events.COMPLETED].repeat_interleave(self.total_num_iters)event_epoch_started=self.event_handlers_times[Events.EPOCH_STARTED].repeat_interleave(iters_per_epoch)event_epoch_completed=self.event_handlers_times[Events.EPOCH_COMPLETED].repeat_interleave(iters_per_epoch)event_iter_started=self.event_handlers_times[Events.ITERATION_STARTED]event_iter_completed=self.event_handlers_times[Events.ITERATION_COMPLETED]event_batch_started=self.event_handlers_times[Events.GET_BATCH_STARTED]event_batch_completed=self.event_handlers_times[Events.GET_BATCH_COMPLETED]results_dump=torch.stack([epochs,iterations,processing_stats,dataflow_stats,event_started,event_completed,event_epoch_started,event_epoch_completed,event_iter_started,event_iter_completed,event_batch_started,event_batch_completed,],dim=1,).numpy()results_df=pd.DataFrame(data=results_dump,columns=["epoch","iteration","processing_stats","dataflow_stats","Event_STARTED","Event_COMPLETED","Event_EPOCH_STARTED","Event_EPOCH_COMPLETED","Event_ITERATION_STARTED","Event_ITERATION_COMPLETED","Event_GET_BATCH_STARTED","Event_GET_BATCH_COMPLETED",],)results_df.to_csv(output_path,index=False)