Machinelearningnotebooks: Relative imports for custom modules

Created on 3 Mar 2020  路  10Comments  路  Source: Azure/MachineLearningNotebooks

I have the following repository structure

root
-code
--main.py
--helper.py

When I deploy a service, I use the following InferenceConfig, from the root level:

inference_config = InferenceConfig(entry_script='code/main.py',
                                   source_directory='.',
                                   environment=environment)

Running everything locally works fine. Even from the command line as python code/main.py. However, as soon as I deploy it as a service I get an ModuleNotFoundError, because the main.py can't find/import the helper (currently done via simple import helper).

I have tried both of these workarounds with no luck:

  • before the import, add sys.path.append('./code')
  • add __init__.py to the /code

What is the right approach to relative module imports in AML, when the deployment is done from the root repository folder and additional modules are in sub-folders?

Inference awaiting-product-team-response machine-learninsvc product-question triaged

All 10 comments

Here a hacky work-around, adding this to the top of your main.py:
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

Further looking into this, i saw that the current working directory ( os.getcwd() ) points to : /var/azureml-app/

This causes issues when trying to load things from the repository, as it is not the same behavior when running the code locally. For example, when trying to retrieve a file from /var/azureml-app/repo-name/assets.

Why is os.getcwd() != /var/azureml-app/repo-name/ ?

@vaidya-s

@Bozhong68

@maknotavailable you can change inference_config to following to make it work:
inference_config = InferenceConfig(entry_script='main.py',
source_directory='code',
environment=environment)

@maknotavailable thanks. I am experiencing the same problem. I don't understand from where we would execute your code. If you use main.py as the entry_script it means you would be inside the code directory? Then source_directory should be .code and not code?

Why is os.getcwd() != /var/azureml-app/repo-name/

In the upcoming SDK release, the current working directory will be changed to the source directory; if one was given in the inference config.

@maknotavailable

I have tried both of these workarounds with no luck:
before the import, add sys.path.append('./code')
add __init__.py to the /code

The problem is that the current working directory (in the current AzureML SDK) is set to the directory above the source directory. So add sys.path.append('./code') wouldn't have worked because it would have needed to be add sys.path.append('./<source_directory_name>/code'). And add __init__.py to the /code doesn't work because it just allows for you do import code and treat the directory as a module.

The fix for this currently is to follow https://docs.microsoft.com/en-us/azure/machine-learning/how-to-deploy-and-where?tabs=azcli#define-an-entry-script . Specifically:

    # If your model were stored in the same directory as your score.py, you could also use the following:
    # model_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'sklearn_mnist_model.pkl')

In @maknotavailable 's situation, this would be (this will work in the current SDK and future releases):

import sys
# add code directory to sys path
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
# should be able to import helper.py in code directory
import helper

after the next SDK release, this should be possible:

from code import helper

@jonringer for providing explanation and solution! @maknotavailable , @Konstantina-Lazaridou I will close the issue now, please feel free to re-open if you still have issues.

I'm trying to accomplish pretty much a similar thing, with one change that i have relative imports in my files.
Due to relative imports, scoring file fails with an error:

ImportError: attempted relative import with no known parent package

iles\modules structure (a simplified version):

project
->src
-> scoring.py
-> module1.py
-> common
-> module2.py, etc
-> init.py
-> init.py
-> configs
-> conda_env.yml

In scoring.py,
from .module1.py import SomeClass
..
..

In module1.py,
from .common.module2.py importSC2
...
..

And below is how an Inference config is initialized:
inference_config = InferenceConfig(source_directory="./",
runtime= "python",
entry_script="src/scoring.py",
conda_file="configs/conda_env.yml"
)

I could not pass entry_script as "src.scoring" as this fails the Validation and relative path to scoring file is expected

@jonringer

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jarandaf picture jarandaf  路  4Comments

jmwoloso picture jmwoloso  路  4Comments

nswitanek picture nswitanek  路  4Comments

chengyu-liu-cs picture chengyu-liu-cs  路  3Comments

dumbledad picture dumbledad  路  3Comments