Repository: Project-MONAI/MONAI
File: monai/apps/auto3dseg/ensemble_builder.py (Python)

Code before:
        if len(history) == 0:
            raise ValueError(
                f"Could not find the trained results in {self.work_dir}. "
                "Possibly the required training step was not completed."
            )

        builder = AlgoEnsembleBuilder(history, self.data_src_cfg_name)
        builder.set_ensemble_method(self.ensemble_method)
        self.ensembler = builder.get_ensemble()
        infer_files = self.ensembler.infer_files
        if len(infer_files) < self.world_size:
            if len(infer_files) == 0:
                logger.info("No existing infer files. Ensembler ending.")
                return
            infer_files = partition_dataset(data=infer_files, shuffle=False,
                                            num_partitions=len(infer_files))[self.rank] \
                                            if self.rank < len(infer_files) else []
        else:
            infer_files = partition_dataset(
                data=infer_files, shuffle=False, num_partitions=self.world_size, even_divisible=True
            )[self.rank]

        # TO DO: Add some function in ensembler for infer_files update?
        self.ensembler.infer_files = infer_files
        # add rank to pred_params
        self.kwargs["rank"] = self.rank
        self.kwargs["image_save_func"] = save_image
        logger.info("Auto3Dseg picked the following networks to ensemble:")
        for algo in self.ensembler.get_algo_ensemble():
            logger.info(algo[AlgoKeys.ID])
        output_dir = save_image["output_dir"]
        logger.info(f"Auto3Dseg ensemble prediction outputs will be saved in {output_dir}.")
        self.ensembler(pred_param=self.kwargs)

        if self.mgpu:
            dist.destroy_process_group()

    def run(self, device_setting: dict | None = None) -> None:
        """
        Load the run function in the training script of each model. Training parameter is predefined by the
        algo_config.yaml file, which is pre-filled by the fill_template_config function in the same instance.

        Args:
            device_setting: device related settings, should follow the device_setting in auto_runner.set_device_info.
                'CUDA_VISIBLE_DEVICES' should be a string e.g. '0,1,2,3'
        """
        # device_setting set default value and sanity check, in case device_setting not from autorunner
        if device_setting is not None:
            self.device_setting.update(device_setting)
            self.device_setting["n_devices"] = len(str(self.device_setting["CUDA_VISIBLE_DEVICES"]).split(","))
        self._create_cmd()

Review comment (bug):
do we need the logic below (including self.ensembler(pred_param=self.kwargs) ) when infer_files is empty list?

are you sure self.ensembler() will not crash with an empty list? may be it's saver to write, 

```
if len(infer_files) >0:
  self.ensembler(...)
  
```
  

Code after:
        if len(history) == 0:
            raise ValueError(
                f"Could not find the trained results in {self.work_dir}. "
                "Possibly the required training step was not completed."
            )

        builder = AlgoEnsembleBuilder(history, self.data_src_cfg_name)
        builder.set_ensemble_method(self.ensemble_method)
        self.ensembler = builder.get_ensemble()
        infer_files = self.ensembler.infer_files
        if len(infer_files) < self.world_size:
            if len(infer_files) == 0:
                logger.info("No testing files for inference is provided. Ensembler ending.")
                return
            infer_files = (
                partition_dataset(data=infer_files, shuffle=False, num_partitions=len(infer_files))[self.rank]
                if self.rank < len(infer_files)
                else []
            )
        else:
            infer_files = partition_dataset(
                data=infer_files, shuffle=False, num_partitions=self.world_size, even_divisible=True
            )[self.rank]

        # TO DO: Add some function in ensembler for infer_files update?
        self.ensembler.infer_files = infer_files
        # add rank to pred_params
        self.kwargs["rank"] = self.rank
        self.kwargs["image_save_func"] = save_image
        logger.info("Auto3Dseg picked the following networks to ensemble:")
        for algo in self.ensembler.get_algo_ensemble():
            logger.info(algo[AlgoKeys.ID])
        output_dir = save_image["output_dir"]
        logger.info(f"Auto3Dseg ensemble prediction outputs will be saved in {output_dir}.")
        self.ensembler(pred_param=self.kwargs)

        if self.mgpu:
            dist.destroy_process_group()

    def run(self, device_setting: dict | None = None) -> None:
        """
        Load the run function in the training script of each model. Training parameter is predefined by the
        algo_config.yaml file, which is pre-filled by the fill_template_config function in the same instance.

        Args:
            device_setting: device related settings, should follow the device_setting in auto_runner.set_device_info.
                'CUDA_VISIBLE_DEVICES' should be a string e.g. '0,1,2,3'
        """
        # device_setting set default value and sanity check, in case device_setting not from autorunner
        if device_setting is not None:
            self.device_setting.update(device_setting)