U Ph@szddlmZddlZddlmZmZddlmZmZm Z m Z m Z ddl m Z ddlmZddlZddlmZddlmZddlmZdd lmZdd lmZmZdd lmZdd lmZm Z dd l!m"Z"m#Z#m$Z$m%Z%m&Z&ddl'm(Z(m)Z)m*Z*ee+Z,dddddddgZ-GdddeZ.Gddde.Z/Gddde.Z0Gddde.Z1Gddde1Z2Gddde.Z3Gddde1Z4dS)) annotationsN)ABCabstractmethod)CallableIterableIteratorMappingSequence)locate)Any) get_logger) MetaTensor) ThreadBuffer) AvgMergerMerger)Splitter)compute_importance_mapsliding_window_inference) BlendMode PatchKeysPytorchPadMode ensure_tupleoptional_import)CAMGradCAM GradCAMppInferer PatchInferer SimpleInfererSlidingWindowInfererSaliencyInferer SliceInfererSlidingWindowInfererAdaptc@s*eZdZdZeddddddddZdS) ra A base class for model inference. Extend this class to support operations during inference, e.g. a sliding window method. Example code:: device = torch.device("cuda:0") transform = Compose([ToTensor(), LoadImage(image_only=True)]) data = transform(img_path).to(device) model = UNet(...).to(device) inferer = SlidingWindowInferer(...) model.eval() with torch.no_grad(): pred = inferer(inputs=data, network=model) ... torch.Tensorrr inputsnetworkargskwargsreturncOstd|jjddS)a Run inference on `inputs` with the `network` model. Args: inputs: input of the model inference. network: model for inference. args: optional args to be passed to ``network``. kwargs: optional keyword args to be passed to ``network``. Raises: NotImplementedError: When the subclass does not override this method. z Subclass z must implement this method.N)NotImplementedError __class____name__selfr%r&r'r(r/K/home/dell461/cl/sdc2/HISourceFinder-master-l/src/monai/inferers/inferer.py__call__AszInferer.__call__N)r, __module__ __qualname____doc__rr1r/r/r/r0r-sc @seZdZdZdeddddddfdddd d d d dd d d ddZdddddZd ddddZddd d ddddZdd Z d!d"Z d#d$Z dd%d d d d&d'd(Z dS))ra& Inference on patches instead of the whole image based on Splitter and Merger. This splits the input image into patches and then merge the resulted patches. Args: splitter: a `Splitter` object that split the inputs into patches. Defaults to None. If not provided or None, the inputs are considered to be already split into patches. In this case, the output `merged_shape` and the optional `cropped_shape` cannot be inferred and should be explicitly provided. merger_cls: a `Merger` subclass that can be instantiated to merges patch outputs. It can also be a string that matches the name of a class inherited from `Merger` class. Defaults to `AvgMerger`. batch_size: batch size for patches. If the input tensor is already batched [BxCxWxH], this adds additional batching [(Bp*B)xCxWpxHp] for inference on patches. Defaults to 1. preprocessing: a callable that process patches before the being fed to the network. Defaults to None. postprocessing: a callable that process the output of the network. Defaults to None. output_keys: if the network output is a dictionary, this defines the keys of the output dictionary to be used for merging. Defaults to None, where all the keys are used. match_spatial_shape: whether to crop the output to match the input shape. Defaults to True. buffer_size: number of patches to be held in the buffer with a separate thread for batch sampling. Defaults to 0. merger_kwargs: arguments to be passed to `merger_cls` for instantiation. `merged_shape` is calculated automatically based on the input shape and the output patch shape unless it is passed here. NTrzSplitter | Noneztype[Merger] | strintzCallable | NonezSequence | Noneboolr None) splitter merger_cls batch_size preprocessingpostprocessing output_keysmatch_spatial_shape buffer_size merger_kwargsr)c Ks2t|t|ttdfs:t|ts:tdt|d||_t|trtd|d\} } | sft |} | dkr~t d|d| }t |t std|d||_ | |_|dk rt|stdt|d||_|dk rt|std t|d||_|d krt d |d||_||_||_||_dS) Nz'splitter' should be a `Splitter` object that returns: an iterable of pairs of (patch, location) or a MetaTensor that has `PatchKeys.LOCATION` metadata).z is given.zmonai.inferers.merger)namezThe requested `merger_cls` ['z'] does not exist.z+'merger' should be a subclass of `Merger`, z-'preprocessing' should be a callable object, z.'postprocessing' should be a callable object, r5z(`batch_size` must be a positive number, )r__init__ isinstancertype TypeErrorr9strrr ValueError issubclassrr:rAcallabler<r=r;r>r?r@) r.r9r:r;r<r=r>r?r@rAZvalid_merger_clsZ merger_foundr/r/r0rCqs<     zPatchInferer.__init__z9Iterable[tuple[torch.Tensor, Sequence[int]]] | MetaTensorz,Iterator[tuple[torch.Tensor, Sequence, int]])patchesr)c cs*t|trdt|}td||jD]@}t|j||}||||||||jtj|fVq n|j dkrt ||j dd}n|}dg|j}dg|j}d}|D]\} | d||<| d||<|d7}||jkrt |||fVdg|j}dg|j}d}q|dkr&t |d|||fVdS)zGenerate batch of patches and locations Args: patches: a tensor or list of tensors Yields: A batch of patches (torch.Tensor or MetaTensor), a sequence of location tuples, and the batch size rg?)r@timeoutNr5) rDr lenranger;minmetarLOCATIONr@rtorchcat) r.rK total_sizeir;bufferZ patch_batchZlocation_batch idx_in_batchsampler/r/r0_batch_samplers, 0         zPatchInferer._batch_samplertuple)outputsr)csFttr:|jdkr"t|_tfdd|jDStddS)Nc3s|]}|VqdSNr/).0kr[r/r0 sz5PatchInferer._ensure_tuple_outputs..T) wrap_array)rDdictr>listkeysrZr)r.r[r/r_r0_ensure_tuple_outputss   z"PatchInferer._ensure_tuple_outputsrr#)r&patchr'r(r)cOs:|jr||}||f||}|jr0||}||Sr\)r<r=re)r.r&rfr'r(r[r/r/r0_run_inferences   zPatchInferer._run_inferencecCst||d}g}g}|D]}t||d} tddt|jdd| jddD} |j} ||| | \} } d| kr| | d<| ddkrtdd| kr| | d<|j f| }| || | q||fS)Nrcss|]\}}||VqdSr\r/)r]ipopr/r/r0r`sz3PatchInferer._initialize_mergers.. merged_shapez `merged_shape` cannot be `None`. cropped_shape) rRchunkrZzipshaperAcopy_get_merged_shapesrHr:append)r.r%r[rKr;in_patchmergersratiosZout_patch_batch out_patchratiorArlrkmergerr/r/r0_initialize_mergerss$,     z PatchInferer._initialize_mergersc CsXt|||D]F\}}}t|t||D](\} } ddt| |D} || | q(q dS)NcSsg|]\}}t||qSr/round)r]lrr/r/r0 sz+PatchInferer._aggregate..)rnrRrm aggregate) r.r[ locationsr;rtruZoutput_patchesrxrwZin_locrvZout_locr/r/r0 _aggregateszPatchInferer._aggregatec Cs|jdkrdS|j|}|j|}tddt||D}tddt||D}|jdd|}|jdd|} |js| }|| fS)z:Define the shape of merged tensors (non-padded and padded)N)NNcss|]\}}t||VqdSr\rzr]sr}r/r/r0r`sz2PatchInferer._get_merged_shapes..css|]\}}t||VqdSr\rzrr/r/r0r`srj)r9Zget_input_shapeZget_padded_shaperZrnror?) r.r%rvrworiginal_spatial_shapeZpadded_spatial_shapeoutput_spatial_shapeZpadded_output_spatial_shaperlrkr/r/r0rqs   zPatchInferer._get_merged_shapesNCallable[..., torch.Tensor | Sequence[torch.Tensor] | dict[Any, torch.Tensor]]r$c Os|jdkrPt|tjrJt|tr6tj|jkrJtdntdt |d|}n ||}g}g}| |D]H\}} } |j ||f||} |s| || || \}}| | | | ||qldd|D} |jrtt|j| St| dkr| dS| S) a Args: inputs: input data for inference, a torch.Tensor, representing an image or batch of images. However if the data is already split, it can be fed by providing a list of tuple (patch, location), or a MetaTensor that has metadata for `PatchKeys.LOCATION`. In both cases no splitter should be provided. network: target model to execute inference. supports callables such as ``lambda x: my_torch_model(x, additional_config)`` args: optional args to be passed to ``network``. kwargs: optional keyword args to be passed to ``network``. Nz`PatchKey.LOCATION` does not exists in `inputs.meta`. If the inputs are already split into patches, the location of patches needs to be provided as `PatchKey.LOCATION` metadata in a MetaTensor. If the input is not already split, please provide `splitter`.z`splitter` should be set if the input is not already split into patches. For inputs that are split, the location of patches needs to be provided as (image, location) pairs, or as `PatchKey.LOCATION` metadata in a MetaTensor. The provided inputs type is .cSsg|] }|qSr/)finalize)r]rxr/r/r0r~Zsz)PatchInferer.__call__..r5r)r9rDrRTensorr rrQrPrHrErYrgryrr>rbrnrM) r.r%r&r'r(Zpatches_locationsrurtrKrr;r[Zmerged_outputsr/r/r0r1$s2      zPatchInferer.__call__) r,r2r3r4rrCrYrergryrrqr1r/r/r/r0rSs""?( c@s4eZdZdZddddZdddddd d d Zd S) rz SimpleInferer is the normal inference method that run model forward() directly. Usage example can be found in the :py:class:`monai.inferers.Inferer` base class. r8)r)cCst|dSr\)rrCr.r/r/r0rCkszSimpleInferer.__init__r#zCallable[..., torch.Tensor]r r$cOs||f||S)aUnified callable function API of Inferers. Args: inputs: model input data for inference. network: target model to execute inference. supports callables such as ``lambda x: my_torch_model(x, additional_config)`` args: optional args to be passed to ``network``. kwargs: optional keyword args to be passed to ``network``. r/r-r/r/r0r1ns zSimpleInferer.__call__Nr,r2r3r4rCr1r/r/r/r0rdscs|eZdZdZddejdejdddddddddfd d d d d d dddddddd dddfdd ZddddddddZZ S)ra Sliding window method for model inference, with `sw_batch_size` windows for every model.forward(). Usage example can be found in the :py:class:`monai.inferers.Inferer` base class. Args: roi_size: the window size to execute SlidingWindow evaluation. If it has non-positive components, the corresponding `inputs` size will be used. if the components of the `roi_size` are non-positive values, the transform will use the corresponding components of img size. For example, `roi_size=(32, -1)` will be adapted to `(32, 64)` if the second spatial dimension size of img is `64`. sw_batch_size: the batch size to run window slices. overlap: Amount of overlap between scans along each spatial dimension, defaults to ``0.25``. mode: {``"constant"``, ``"gaussian"``} How to blend output of overlapping windows. Defaults to ``"constant"``. - ``"constant``": gives equal weight to all predictions. - ``"gaussian``": gives less weight to predictions on edges of windows. sigma_scale: the standard deviation coefficient of the Gaussian window when `mode` is ``"gaussian"``. Default: 0.125. Actual window sigma is ``sigma_scale`` * ``dim_size``. When sigma_scale is a sequence of floats, the values denote sigma_scale at the corresponding spatial dimensions. padding_mode: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``} Padding mode when ``roi_size`` is larger than inputs. Defaults to ``"constant"`` See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html cval: fill value for 'constant' padding mode. Default: 0 sw_device: device for the window data. By default the device (and accordingly the memory) of the `inputs` is used. Normally `sw_device` should be consistent with the device where `predictor` is defined. device: device for the stitched output prediction. By default the device (and accordingly the memory) of the `inputs` is used. If for example set to device=torch.device('cpu') the gpu memory consumption is less and independent of the `inputs` and `roi_size`. Output is on the `device`. progress: whether to print a tqdm progress bar. cache_roi_weight_map: whether to precompute the ROI weight map. cpu_thresh: when provided, dynamically switch to stitching on cpu (to save gpu memory) when input image volume is larger than this threshold (in pixels/voxels). Otherwise use ``"device"``. Thus, the output may end-up on either cpu or gpu. buffer_steps: the number of sliding window iterations along the ``buffer_dim`` to be buffered on ``sw_device`` before writing to ``device``. (Typically, ``sw_device`` is ``cuda`` and ``device`` is ``cpu``.) default is None, no buffering. For the buffer dim, when spatial size is divisible by buffer_steps*roi_size, (i.e. no overlapping among the buffers) non_blocking copy may be automatically enabled for efficiency. buffer_dim: the spatial dimension along which the buffers are created. 0 indicates the first spatial dimension. Default is -1, the last spatial dimension. with_coord: whether to pass the window coordinates to ``network``. Defaults to False. If True, the ``network``'s 2nd input argument should accept the window coordinates. Note: ``sw_batch_size`` denotes the max number of windows per network inference iteration, not the batch size of inputs. r5g?g?gNFzSequence[int] | intr6zSequence[float] | floatzBlendMode | strzPytorchPadMode | strfloatztorch.device | str | Noner7 int | Noner8)roi_size sw_batch_sizeoverlapmode sigma_scale padding_modecval sw_devicedeviceprogresscache_roi_weight_map cpu_thresh buffer_steps buffer_dim with_coordr)c st||_||_||_t||_||_||_||_ ||_ | |_ | |_ | |_ | |_||_||_d|_zZ| rt|trt|dkr| dkrd} tt|j||| d|_| r|jdkrtdWnJtk r }z*td|jd|d|d| d |W5d}~XYnXdS) Nrcpu)rrrzHcache_roi_weight_map=True, but cache is not created. (dynamic roi_size?)z roi size z, mode=z, sigma_scale=z , device=z^ Seems to be OOM. Please try smaller patch size or mode='constant' instead of mode='gaussian'.)superrCrrrrrrrrrrrrrrrroi_weight_maprDr rOrrwarningswarn BaseException RuntimeError)r.rrrrrrrrrrrrrrrer+r/r0rCsD  zSlidingWindowInferer.__init__r#rr Atorch.Tensor | tuple[torch.Tensor, ...] | dict[Any, torch.Tensor]r$cOs|d|j}|d|j}|d|j}|dkrX|jdk rX|jdd|jkrXd}t||j|j ||j |j |j |j |j|j||j|jd|||jf||S)g Args: inputs: model input data for inference. network: target model to execute inference. supports callables such as ``lambda x: my_torch_model(x, additional_config)`` args: optional args to be passed to ``network``. kwargs: optional keyword args to be passed to ``network``. rrrNrjr)poprrrrronumelrrrrrrrrrrrr)r.r%r&r'r(rrrr/r/r0r1s8*zSlidingWindowInferer.__call__) r,r2r3r4rCONSTANTrrCr1 __classcell__r/r/rr0r~s":24cs.eZdZdZddddddfdd ZZS) r"a( SlidingWindowInfererAdapt extends SlidingWindowInferer to automatically switch to buffered and then to CPU stitching, when OOM on GPU. It also records a size of such large images to automatically try CPU stitching for the next large image of a similar size. If the stitching 'device' input parameter is provided, automatic adaptation won't be attempted, please keep the default option device = None for adaptive behavior. Note: the output might be on CPU (even if the input was on GPU), if the GPU memory was not sufficient. r#rr rr$c s`|jdk r tj||f||S|jdk o2|jdk}|jdk oT|jdd|jk}|jo`| }|jop|op| }|jdk rtd|jnd} d} t |jdd} | t| } |j| d|jddkr| } t dD]Z} zBtj||f||r|jnt d|r | nd| d|WSt k r2}z|s@|rTd tt|jkrX|t||rd }|jddd|_|rd }td |jd n*d }| |_td| d| d|jd nR| dkr td| d} | |_td|jd| d nd }td|jd W5d}~XYqXqt d|d|d|d|d| dS)rNrrjr5r r)rrrOutOfMemoryErrorFz3GPU stitching failed, attempting on CPU, image dim rTzGPU stitching failed, buffer z dim z , image dim z)GPU buffered stitching failed, image dim z reducing buffer to zeZdZdZdddddddddd Zd d ddd d dZdS)r a SaliencyInferer is inference with activation maps. Args: cam_name: expected CAM method name, should be: "CAM", "GradCAM" or "GradCAMpp". target_layers: name of the model layer to generate the feature map. class_idx: index of the class to be visualized. if None, default to argmax(logits). args: other optional args to be passed to the `__init__` of cam. kwargs: other optional keyword args to be passed to `__init__` of cam. NrGrr r8)cam_name target_layers class_idxr'r(r)cOsDt||dkrtd||_||_||_||_||_dS)N)camgradcamZ gradcamppz4cam_name should be: 'CAM', 'GradCAM' or 'GradCAMpp'.) rrClowerrHrrrr'r()r.rrrr'r(r/r/r0rCs   zSaliencyInferer.__init__r#z nn.Module)r%r&r'r(cOst|jdkr$t||jf|j|j}n<|jdkrHt||jf|j|j}nt||jf|j|j}|||jf||S)aUnified callable function API of Inferers. Args: inputs: model input data for inference. network: target model to execute inference. supports callables such as ``lambda x: my_torch_model(x, additional_config)`` args: other optional args to be passed to the `__call__` of cam. kwargs: other optional keyword args to be passed to `__call__` of cam. rr)rrrr'r(rrr)r.r%r&r'r(rr/r/r0r1s  zSaliencyInferer.__call__)Nrr/r/r/r0r ss  cs^eZdZdZddddddfdd Zd d ddd d fd d Zd d ddd dddZZS)r!a[ SliceInferer extends SlidingWindowInferer to provide slice-by-slice (2D) inference when provided a 3D volume. A typical use case could be a 2D model (like 2D segmentation UNet) operates on the slices from a 3D volume, and the output is a 3D volume with 2D slices aggregated. Example:: # sliding over the `spatial_dim` inferer = SliceInferer(roi_size=(64, 256), sw_batch_size=1, spatial_dim=1) output = inferer(input_volume, net) Args: spatial_dim: Spatial dimension over which the slice-by-slice inference runs on the 3D volume. For example ``0`` could slide over axial slices. ``1`` over coronal slices and ``2`` over sagittal slices. args: other optional args to be passed to the `__init__` of base class SlidingWindowInferer. kwargs: other optional keyword args to be passed to `__init__` of base class SlidingWindowInferer. Note: ``roi_size`` in SliceInferer is expected to be a 2D tuple when a 3D volume is provided. This allows sliding across slices along the 3D volume using a selected ``spatial_dim``. rr6r r8) spatial_dimr'r(r)cs$||_tj||t|j|_dSr\)rrrCrr orig_roi_size)r.rr'r(rr/r0rCszSliceInferer.__init__r#rrr$csjdkrtdtj_tjdkr`t|jdddkr`tj_jjdnt djd|jdt j |fd d d S) a Args: inputs: 3D input for inference network: 2D model to execute inference on slices in the 3D input args: optional args to be passed to ``network``. kwargs: optional keyword args to be passed to ``network``. rjzB`spatial_dim` can only be `0, 1, 2` with `[H, W, D]` respectively.Nr5zCurrently, only 2D `roi_size` (z!) with 3D `inputs` tensor (shape=z) is supported.csj|fSr\)network_wrapper)xr'r(r&r.r/r0z'SliceInferer.__call__..)r%r&) rrHrrrMrrorcinsertrrr1r-rrr0r1s  $ zSliceInferer.__call__)r&rr'r(r)cs|jjdd}||f||}t|tjr@|jjddSt|trv|D]}||jjdd||<qR|Stfdd|DS)zP Wrapper handles inference for 2D models over 3D volume inputs. rjdimc3s |]}|jjddVqdS)rjrN) unsqueezer)r]out_irr/r0r`sz/SliceInferer.network_wrapper..) squeezerrDrRrrrrdrZ)r.r&rr'r(outr^r/rr0rs    zSliceInferer.network_wrapper)r)r,r2r3r4rCr1rrr/r/rr0r!s)5 __future__rrabcrrcollections.abcrrrrr pydocr typingr rRtorch.nnnnmonai.apps.utilsr monai.data.meta_tensorr Zmonai.data.thread_bufferrZmonai.inferers.mergerrrZmonai.inferers.splitterrZmonai.inferers.utilsrr monai.utilsrrrrrZmonai.visualizerrrr,r__all__rrrrr"r r!r/r/r/r0 sD         &Y/