U Ph#= @sdZddlmZddlZddlmZmZddlmZddl m Z m Z ddl m Z mZddlZddlZddlmZdd lmZmZzddlmZd ZWnek rd ZYnXe rdd lmZmZn(ed ejed\ZZ ed ejed\ZZ dZ!de!fdfddddddddddZ"de!fdfdddddddddd d!Z#dd"d#d$d%d&Z$d'de!fde$ddfdd(ddddd)d*dd+d, d-d.Z%d/d"d0d1d2Z&Gd3d4d4eZ'Gd5d6d6e Z(dS)7z This set of utility function is meant to make using Jupyter notebooks easier with MONAI. Plotting functions using Matplotlib produce common plots for metrics and images. ) annotationsN)CallableMapping)Enum)RLockThread) TYPE_CHECKINGAny) IgniteInfo) min_versionoptional_importTF)EngineEventsz ignite.enginer rlosslogzplt.Axesstrz;Mapping[str, list[float] | tuple[list[float], list[float]]]z tuple[str]intNone)axtitlegraphmapyscaleavg_keyswindow_fractionreturncCsHddlm}|D]\}}t|dkrt|dttfrHt|\} } nttt|t|} } |j | | |d| ddd||krt||krt||} t | f| } t j | df| d| | dd } |j | | |d | dddq| ||||d |jd dd d|ddd|j|dddS)ar Plot metrics on a single graph with running averages plotted for selected keys. The values in `graphmap` should be lists of (timepoint, value) pairs as stored in MetricLogger objects. Args: ax: Axes object to plot into title: graph title graphmap: dictionary of named graph values, which are lists of values or (index, value) pairs yscale: scale for y-axis compatible with `Axes.set_yscale` avg_keys: tuple of keys in `graphmap` to provide running average plots for window_fraction: what fraction of the graph value length to use as the running average window r) MaxNLocatorz = z.5g)labelvalid)modez Avg = on)rrg)Zbbox_to_anchorlocZ borderaxespadTboth)integerN)Zmatplotlib.tickerritemslen isinstancetuplelistziprangeplotnponesconvolve set_title set_yscaleaxislegendgridxaxisZset_major_locator)rrrrrrrnvindsvalswindowkernelrar>N/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/utils/jupyter_utils.pyplot_metric_graph.s$    ""   r@z plt.Figurezdict[str, np.ndarray]r*)figrrimagemaprrrrc Csdtdt|f}tj|d|d|d}t|||||||g} t|D]\} } tj|d| fd|d} || jddkr| || dddgn| jt || d d | | d ||  d d || d | d| | qH| S)a Plot metric graph data with images below into figure `fig`. The intended use is for the graph data to be metrics from a training run and the images to be the batch and output from the last iteration. This uses `plot_metric_graph` to plot the metric graph. Args: fig: Figure object to plot into, reuse from previous plotting for flicker-free refreshing title: graph title graphmap: dictionary of named graph values, which are lists of values or (index, value) pairs imagemap: dictionary of named images to show with metric plot yscale: for metric plot, scale for y-axis compatible with `Axes.set_yscale` avg_keys: for metric plot, tuple of keys in `graphmap` to provide running average plots for window_fraction: for metric plot, what fraction of the graph value length to use as the running average window Returns: list of Axes objects for graph followed by images r)rr)colspanrA)rowspanrArZgray)cmap z.3gz -> off)maxr'pltZ subplot2gridr@ enumerateshapeimshow transposer.squeezer1minr3append) rArrrBrrrZ gridshapegraphaxesir7imr>r>r?plot_metric_images]s.  rX torch.Tensorznp.ndarray | None)nametensorrcCs|jdkr4|jddkr4|jddkr4|jS|jdkr|jddkr|jddkr|jdd}|dd|fjSdS)a Return an tuple of images derived from the given tensor. The `name` value indices which key from the output or batch value the tensor was stored as, or is "Batch" or "Output" if these were single tensors instead of dictionaries. Returns a tuple of 2D images of shape HW, or 3D images of shape CHW where C is color channels RGB or RGBA. This allows multiple images to be created from a single tensor, ie. to show each channel separately. rGrrErCN)ndimrNcpudatanumpy)rZr[Zdmidr>r>r?tensor_to_imagess &&r`z Training Logr z)Callable[[str, torch.Tensor], Any] | Noneplt.Figure | Noneztuple[plt.Figure, list]) engineloggerrrrrimage_fnrA selected_instrc Cs|dk r|ntjdddd}t|ji} | |ji} |dk rX|jdk rX|jjdk rX|jj|jj fD]} | |jjkrdnd} |} t | t r| |}d} d d | D} t | t r&| D]Z\}}t |tjr|jd kr|||| }|dk rt|D]\}}|| |d |<qqqpt | tjrp|| | }|dk rp|| | d |<qpt||| | |||}|jr|dj|jd dddd||fS)a Plot the status of the given Engine with its logger. The plot will consist of a graph of loss values and metrics taken from the logger, and images taken from the `output` and `batch` members of `engine.state`. The images are converted to Numpy arrays suitable for input to `Axes.imshow` using `image_fn`, if this is None then no image plotting is done. Args: engine: Engine to extract images from logger: MetricLogger to extract loss and metric data from title: graph title yscale: for metric plot, scale for y-axis compatible with `Axes.set_yscale` avg_keys: for metric plot, tuple of keys in `graphmap` to provide running average plots for window_fraction: for metric plot, what fraction of the graph value length to use as the running average window image_fn: callable converting tensors keyed to a name in the Engine to a tuple of images to plot fig: Figure object to plot into, reuse from previous plotting for flicker-free refreshing selected_inst: index of the instance to show in the image plot Returns: Figure object (or `fig` if given), list of Axes objects for graph and images N)r Twhite)figsize tight_layout facecolorZBatchOutputrcSs0i|](\}}t|tjr|jdkr||dqS)rGN)r(torchTensorr\).0kr8r>r>r? s  z&plot_engine_status..rC_rrro:)cls)ZclfrLFigure LOSS_NAMErupdatemetricsstatebatchoutputr(r*r&dictrlrmr\rMrXZaxhline)rbrcrrrrrdrArerrBsrcrZbatch_selected_instZ selected_dictror8imagerVrWrUr>r>r?plot_engine_statuss:   $    rzUlist[torch.Tensor | dict[str, torch.Tensor]] | dict[str, torch.Tensor] | torch.Tensor)r{rcCs.ddddd}t|tr&||dS||S)zJReturns a single value from the network output, which is a dict or tensor.z&torch.Tensor | dict[str, torch.Tensor]rY)r^rcSst|tr|dS|S)Nr)r(r|)r^r>r>r? _get_losss z(_get_loss_from_output.._get_lossr)r(r*)r{rr>r>r?_get_loss_from_outputs  rc@s eZdZdZdZdZdZdZdS) StatusMembersz` Named members of the status dictionary, others may be present for named metric values. StatusZEpochsZItersZLossN)__name__ __module__ __qualname____doc__STATUSEPOCHSITERSLOSSr>r>r>r?rs rcseZdZdZedddfdddddfd d Zd d Zd dZddZe ddddZ ddddZ e fddddddZ ZS)ThreadContainera Contains a running `Engine` object within a separate thread from main thread in a Jupyter notebook. This allows an engine to begin a run in the background and allow the starting notebook cell to complete. A user can thus start a run and then navigate away from the notebook without concern for loosing connection with the running cell. All output is acquired through methods which synchronize with the running engine using an internal `lock` member, acquiring this lock allows the engine to be inspected while it's prevented from starting the next iteration. Args: engine: wrapped `Engine` object, when the container is started its `run` method is called loss_transform: callable to convert an output dict into a single numeric value metric_transform: callable to convert a named metric value into a single numeric value status_format: format string for status key-value pairs. cCs|SNr>)rZvaluer>r>r?zThreadContainer.z {}: {:.4}r rr)rbloss_transformmetric_transform status_formatcsLtt|_||_i|_||_||_d|_||_ |j t j |j dSr)super__init__rlockrb _status_dictrrrArZadd_event_handlerrZITERATION_COMPLETED_update_status)selfrbrrr __class__r>r?rs zThreadContainer.__init__cCs|jdS)z-Calls the `run` method of the wrapped engine.N)rbrunrr>r>r?r(szThreadContainer.runcCs|j|dS)z$Stop the engine and join the thread.N)rb terminatejoinrr>r>r?stop,s zThreadContainer.stopc Cs |j|jj}tjjdtjjdtjjtdi}|dk r|j dk rd|j dkrd|j d|j }n t |j }|j dk r|j |j d|j }n t |j }||tjj<||tjj<||j|tjj<|jpi}|D]*\}}|||}|dk r|||q|j|W5QRXdS)zNCalled as an event, updates the internal status dict at the end of iterations.rnanNr/)rrbryrrrrrfloatZ max_epochsepochrZ epoch_length iterationrr{rxr&rrSrrw)rrystatsritersrxmr8r>r>r?r1s2         zThreadContainer._update_statuszdict[str, str])rc CsF|j6tjj|rdndi}||j|W5QRSQRXdS)zTA dictionary containing status information, current loss, and current metric values.ZRunningZStoppedN)rrrris_aliverwr)rrr>r>r? status_dictRs zThreadContainer.status_dictcCst|j}|tjjdt|tjjdg}| D]:\}}t |t r\|j ||}n|d|}||q:d|S)zr>r?statusZs &  zThreadContainer.statusr ra)rc plot_funcrc CsB|j2|||j||jd\|_}|jW5QRSQRXdS)a$ Generate a plot of the current status of the contained engine whose loss and metrics were tracked by `logger`. The function `plot_func` must accept arguments `title`, `engine`, `logger`, and `fig` which are the plot title, `self.engine`, `logger`, and `self.fig` respectively. The return value must be a figure object (stored in `self.fig`) and a list of Axes objects for the plots in the figure. Only the figure is returned by this method, which holds the internal lock during the plot generation. )rrbrcrAN)rrrbrA)rrcrrqr>r>r? plot_statusjszThreadContainer.plot_status)rrrrrrrrrpropertyrrrr __classcell__r>r>rr?rs!r))r __future__rrcollections.abcrrenumr threadingrrtypingrr r_r.rl monai.configr monai.utils.moduler r matplotlib.pyplotpyplotrLZhas_matplotlib ImportError ignite.enginer rOPT_IMPORT_VERSIONrqrvr@rXr`rrrrr>r>r>r? sP     40"N