def submit_for_inference(args: SubmitForInferenceConfig, azure_config: AzureConfig) -> Optional[Path]: """ Create and submit an inference to AzureML, and optionally download the resulting segmentation. :param azure_config: An object with all necessary information for accessing Azure. :param args: configuration, see SubmitForInferenceConfig :return: path to downloaded segmentation on local disc, or None if none. """ logging.info(f"Building Azure configuration from {args.settings}") logging.info("Getting workspace") workspace = azure_config.get_workspace() logging.info("Identifying model") model = Model(workspace=workspace, id=args.model_id) model_id = model.id logging.info(f"Identified model {model_id}") source_directory = tempfile.TemporaryDirectory() source_directory_name = source_directory.name logging.info( f"Building inference run submission in {source_directory_name}") source_directory_path = Path(source_directory_name) copy_image_file(args.image_file, source_directory_path / DEFAULT_DATA_FOLDER) # We copy over run_scoring.py, and score.py as well in case the model we're using # does not have sufficiently recent versions of those files. for base in ["run_scoring.py", "score.py"]: shutil.copyfile(base, str(source_directory_path / base)) source_config = SourceConfig( root_folder=source_directory_name, entry_script=str(source_directory_path / "run_scoring.py"), script_params={ "--data-folder": ".", "--spawnprocess": "python", "--model-id": model_id, "score.py": "" }, conda_dependencies_files=download_conda_dependency_files( model, source_directory_path)) estimator = create_estimator_from_configs(workspace, azure_config, source_config, []) exp = Experiment(workspace=workspace, name=args.experiment_name) run = exp.submit(estimator) logging.info(f"Submitted run {run.id} in experiment {run.experiment.name}") logging.info(f"Run URL: {run.get_portal_url()}") if not args.keep_upload_folder: source_directory.cleanup() logging.info(f"Deleted submission directory {source_directory_name}") if args.download_folder is None: return None logging.info("Awaiting run completion") run.wait_for_completion() logging.info(f"Run has completed with status {run.get_status()}") download_path = choose_download_path(args.download_folder) logging.info(f"Attempting to download segmentation to {download_path}") run.download_file(DEFAULT_RESULT_IMAGE_NAME, str(download_path)) if download_path.exists(): logging.info(f"Downloaded segmentation to {download_path}") else: logging.warning("Segmentation NOT downloaded") return download_path
def submit_for_inference(args: SubmitForInferenceConfig, azure_config: AzureConfig) -> Optional[Path]: """ Create and submit an inference to AzureML, and optionally download the resulting segmentation. :param azure_config: An object with all necessary information for accessing Azure. :param args: configuration, see SubmitForInferenceConfig :return: path to downloaded segmentation on local disc, or None if none. """ logging.info(f"Building Azure configuration from {args.settings}") logging.info("Getting workspace") workspace = azure_config.get_workspace() logging.info("Identifying model") model = Model(workspace=workspace, id=args.model_id) model_id = model.id logging.info(f"Identified model {model_id}") source_directory = tempfile.TemporaryDirectory() source_directory_path = Path(source_directory.name) logging.info( f"Building inference run submission in {source_directory_path}") image_folder = source_directory_path / fixed_paths.DEFAULT_DATA_FOLDER image = copy_image_file(args.image_file, image_folder) model_sas_urls = model.get_sas_urls() # Identifies all the files with basename "environment.yml" in the model and downloads them. # These downloads should go into a temp folder that will most likely not be included in the model itself, # because the AzureML run will later download the model into the same folder structure, and the file names might # clash. temp_folder = source_directory_path / "temp_for_scoring" conda_files = download_files_from_model(model_sas_urls, ENVIRONMENT_YAML_FILE_NAME, dir_path=temp_folder) if not conda_files: raise ValueError( "At least 1 Conda environment definition must exist in the model.") # Copy the scoring script from the repository. This will start the model download from Azure, and invoke the # scoring script. entry_script = source_directory_path / Path( fixed_paths.RUN_SCORING_SCRIPT).name shutil.copyfile( str( fixed_paths.repository_root_directory( fixed_paths.RUN_SCORING_SCRIPT)), str(entry_script)) source_config = SourceConfig( root_folder=source_directory_path, entry_script=entry_script, script_params={ "--model-folder": ".", "--model-id": model_id, fixed_paths.SCORE_SCRIPT: "", # The data folder must be relative to the root folder of the AzureML job. test_image_files # is then just the file relative to the data_folder "--data_folder": image.parent.name, "--image_files": image.name }, conda_dependencies_files=conda_files, ) estimator = create_estimator_from_configs(azure_config, source_config, []) exp = Experiment(workspace=workspace, name=args.experiment_name) run = exp.submit(estimator) logging.info(f"Submitted run {run.id} in experiment {run.experiment.name}") logging.info(f"Run URL: {run.get_portal_url()}") if not args.keep_upload_folder: source_directory.cleanup() logging.info(f"Deleted submission directory {source_directory_path}") if args.download_folder is None: return None logging.info("Awaiting run completion") run.wait_for_completion() logging.info(f"Run has completed with status {run.get_status()}") download_path = choose_download_path(args.download_folder) logging.info(f"Attempting to download segmentation to {download_path}") run.download_file(DEFAULT_RESULT_IMAGE_NAME, str(download_path)) if download_path.exists(): logging.info(f"Downloaded segmentation to {download_path}") else: logging.warning("Segmentation NOT downloaded") return download_path