Unverified Commit 80b6cb3b authored by liuzhe-lz's avatar liuzhe-lz Committed by GitHub
Browse files

Merge pull request #3030 from microsoft/v2.0

Merge v2.0 into master
parents 77dac12b ff1af7f2
...@@ -9,8 +9,8 @@ import json_tricks ...@@ -9,8 +9,8 @@ import json_tricks
from schema import And from schema import And
from . import parameter_expressions from . import parameter_expressions
from .common import init_logger from .runtime.common import init_logger
from .env_vars import dispatcher_env_vars from .runtime.env_vars import dispatcher_env_vars
to_json = functools.partial(json_tricks.dumps, allow_nan=True) to_json = functools.partial(json_tricks.dumps, allow_nan=True)
......
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
"""
TypeScript modules of NNI.
As a python package this only contains "package data".
"""
# Copyright (c) Microsoft Corporation. # Copyright (c) Microsoft Corporation.
# Licensed under the MIT license. # Licensed under the MIT license.
"""
Script for installation and distribution.
You can use environment variable `NNI_RELEASE` to set release version.
If release version is not set, default to a development build whose version string will be `999.dev0`.
## Development ##
Build and install for development:
$ python setup.py develop
Uninstall:
$ pip uninstall nni
Remove generated files: (use "--all" to remove toolchain and built wheel)
$ python setup.py clean [--all]
Build TypeScript modules without install:
$ python setup.py build_ts
## Release ##
Build wheel package:
$ NNI_RELEASE=2.0 python setup.py build_ts
$ NNI_RELEASE=2.0 python setup.py bdist_wheel -p manylinux1_x86_64
Where "2.0" is version string and "manylinux1_x86_64" is platform.
The platform may also be "macosx_10_9_x86_64" or "win_amd64".
`build_ts` must be manually invoked before `bdist_wheel`,
or setuptools cannot locate JS files which should be packed into wheel.
"""
from distutils.cmd import Command
from distutils.command.build import build
from distutils.command.clean import clean
import glob
import os import os
from setuptools import setup, find_packages import shutil
def read(fname): import setuptools
return open(os.path.join(os.path.dirname(__file__), fname), encoding='utf-8').read() from setuptools.command.develop import develop
setup( import setup_ts
name = 'nni',
version = '999.0.0-developing',
author = 'Microsoft NNI Team', dependencies = [
author_email = 'nni@microsoft.com', 'astor',
description = 'Neural Network Intelligence project', 'hyperopt==0.1.2',
long_description = read('README.md'), 'json_tricks',
license = 'MIT', 'netifaces',
url = 'https://github.com/Microsoft/nni', 'numpy',
'psutil',
packages = find_packages('src/sdk/pynni', exclude=['tests']) + find_packages('src/sdk/pycli') + find_packages('tools'), 'ruamel.yaml',
package_dir = { 'requests',
'nni': 'src/sdk/pynni/nni', 'responses',
'nnicli': 'src/sdk/pycli/nnicli', 'scipy',
'nni_annotation': 'tools/nni_annotation', 'schema',
'nni_cmd': 'tools/nni_cmd', 'PythonWebHDFS',
'nni_trial_tool':'tools/nni_trial_tool', 'colorama',
'nni_gpu_tool':'tools/nni_gpu_tool' 'scikit-learn>=0.23.2',
}, 'pkginfo',
package_data = {'nni': ['**/requirements.txt']}, 'websockets'
python_requires = '>=3.6', ]
install_requires = [
'astor',
'hyperopt==0.1.2', release = os.environ.get('NNI_RELEASE')
'json_tricks',
'netifaces', def _setup():
'numpy', setuptools.setup(
'psutil', name = 'nni',
'ruamel.yaml', version = release or '999.dev0',
'requests', description = 'Neural Network Intelligence project',
'responses', long_description = open('README.md', encoding='utf-8').read(),
'scipy', long_description_content_type = 'text/markdown',
'schema', url = 'https://github.com/Microsoft/nni',
'PythonWebHDFS', author = 'Microsoft NNI Team',
'colorama', author_email = 'nni@microsoft.com',
'scikit-learn>=0.23.2', license = 'MIT',
'pkginfo', classifiers = [
'websockets' 'License :: OSI Approved :: MIT License',
], 'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows :: Windows 10',
entry_points = { 'Operating System :: POSIX :: Linux',
'console_scripts' : [ 'Programming Language :: Python :: 3 :: Only',
'nnictl = nni_cmd.nnictl:parse_args' 'Topic :: Scientific/Engineering :: Artificial Intelligence',
] ],
}
) packages = _find_python_packages(),
package_data = {
'nni': ['**/requirements.txt'],
'nni_node': _find_node_files() # note: this does not work before building
},
python_requires = '>=3.6',
install_requires = dependencies,
setup_requires = ['requests'],
entry_points = {
'console_scripts' : [
'nnictl = nni.tools.nnictl.nnictl:parse_args'
]
},
cmdclass = {
'build': Build,
'build_ts': BuildTs,
'clean': Clean,
'develop': Develop,
}
)
def _find_python_packages():
packages = []
for dirpath, dirnames, filenames in os.walk('nni'):
if '/__pycache__' not in dirpath:
packages.append(dirpath.replace('/', '.'))
return sorted(packages) + ['nni_node']
def _find_node_files():
files = []
for dirpath, dirnames, filenames in os.walk('nni_node'):
for filename in filenames:
files.append((dirpath + '/' + filename)[len('nni_node/'):])
files.remove('__init__.py')
return sorted(files)
class BuildTs(Command):
description = 'build TypeScript modules'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
setup_ts.build(release)
class Build(build):
def run(self):
assert release, 'Please set environment variable "NNI_RELEASE=<release_version>"'
assert os.path.isfile('nni_node/main.js'), 'Please run "build_ts" before "build"'
assert not os.path.islink('nni_node/main.js'), 'This is a development build'
super().run()
class Develop(develop):
def finalize_options(self):
self.user = True # always use `develop --user`
super().finalize_options()
def run(self):
setup_ts.build(release=None)
super().run()
class Clean(clean):
def finalize_options(self):
self._all = self.all
self.all = True # always use `clean --all`
super().finalize_options()
def run(self):
super().run()
setup_ts.clean(self._all)
_clean_temp_files()
shutil.rmtree('nni.egg-info', ignore_errors=True)
if self._all:
shutil.rmtree('dist', ignore_errors=True)
def _clean_temp_files():
for pattern in _temp_files:
for path in glob.glob(pattern):
if os.path.islink(path) or os.path.isfile(path):
os.remove(path)
else:
shutil.rmtree(path)
_temp_files = [
# unit test
'test/model_path/',
'test/temp.json',
'test/ut/sdk/*.pth'
]
_setup()
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
"""
Script for building TypeScript modules.
This script is called by `setup.py` and common users should avoid using this directly.
It compiles TypeScript source files in `ts` directory,
and copies (or links) JavaScript output as well as dependencies to `nni_node`.
You can set environment `GLOBAL_TOOLCHAIN=1` to use global node and yarn, if you know what you are doing.
"""
from io import BytesIO
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tarfile
from zipfile import ZipFile
node_version = 'v10.22.1'
yarn_version = 'v1.22.10'
def build(release):
"""
Compile TypeScript modules and copy or symlink to nni_node directory.
`release` is the version number without leading letter "v".
If `release` is None or empty, this is a development build and uses symlinks;
otherwise this is a release build and copies files instead.
"""
if release or not os.environ.get('GLOBAL_TOOLCHAIN'):
download_toolchain()
compile_ts()
if release:
copy_nni_node(release)
else:
symlink_nni_node()
def clean(clean_all=False):
"""
Remove TypeScript-related intermediate files.
Python intermediate files are not touched here.
"""
clear_nni_node()
for path in generated_directories:
shutil.rmtree(path, ignore_errors=True)
if clean_all:
shutil.rmtree('toolchain', ignore_errors=True)
Path('nni_node', node_executable).unlink()
if sys.platform == 'linux' or sys.platform == 'darwin':
node_executable = 'node'
node_spec = f'node-{node_version}-{sys.platform}-x64'
node_download_url = f'https://nodejs.org/dist/latest-v10.x/{node_spec}.tar.xz'
node_extractor = lambda data: tarfile.open(fileobj=BytesIO(data), mode='r:xz')
node_executable_in_tarball = 'bin/node'
elif sys.platform == 'win32':
node_executable = 'node.exe'
node_spec = f'node-{node_version}-win-x64'
node_download_url = f'https://nodejs.org/dist/latest-v10.x/{node_spec}.zip'
node_extractor = lambda data: ZipFile(BytesIO(data))
node_executable_in_tarball = 'node.exe'
else:
raise RuntimeError('Unsupported system')
yarn_executable = 'yarn' if sys.platform != 'win32' else 'yarn.cmd'
yarn_download_url = f'https://github.com/yarnpkg/yarn/releases/download/{yarn_version}/yarn-{yarn_version}.tar.gz'
def download_toolchain():
"""
Download and extract node and yarn,
then copy node executable to nni_node directory.
"""
if Path('nni_node', node_executable).is_file():
return
Path('toolchain').mkdir(exist_ok=True)
import requests # place it here so setup.py can install it before importing
_print(f'Downloading node.js from {node_download_url}')
resp = requests.get(node_download_url)
resp.raise_for_status()
_print('Extracting node.js')
tarball = node_extractor(resp.content)
tarball.extractall('toolchain')
shutil.rmtree('toolchain/node', ignore_errors=True)
Path('toolchain', node_spec).rename('toolchain/node')
_print(f'Downloading yarn from {yarn_download_url}')
resp = requests.get(yarn_download_url)
resp.raise_for_status()
_print('Extracting yarn')
tarball = tarfile.open(fileobj=BytesIO(resp.content), mode='r:gz')
tarball.extractall('toolchain')
shutil.rmtree('toolchain/yarn', ignore_errors=True)
Path(f'toolchain/yarn-{yarn_version}').rename('toolchain/yarn')
src = Path('toolchain/node', node_executable_in_tarball)
dst = Path('nni_node', node_executable)
shutil.copyfile(src, dst)
def compile_ts():
"""
Use yarn to download dependencies and compile TypeScript code.
"""
_print('Building NNI manager')
_yarn('ts/nni_manager')
_yarn('ts/nni_manager', 'build')
# todo: I don't think these should be here
shutil.rmtree('ts/nni_manager/dist/config', ignore_errors=True)
shutil.copytree('ts/nni_manager/config', 'ts/nni_manager/dist/config')
_print('Building web UI')
_yarn('ts/webui')
_yarn('ts/webui', 'build')
_print('Building NAS UI')
_yarn('ts/nasui')
_yarn('ts/nasui', 'build')
def symlink_nni_node():
"""
Create symlinks to compiled JS files.
If you manually modify and compile TS source files you don't need to install again.
"""
_print('Creating symlinks')
clear_nni_node()
for path in Path('ts/nni_manager/dist').iterdir():
_symlink(path, Path('nni_node', path.name))
_symlink('ts/nni_manager/package.json', 'nni_node/package.json')
_symlink('ts/nni_manager/node_modules', 'nni_node/node_modules')
_symlink('ts/webui/build', 'nni_node/static')
Path('nni_node/nasui').mkdir(exist_ok=True)
_symlink('ts/nasui/build', 'nni_node/nasui/build')
_symlink('ts/nasui/server.js', 'nni_node/nasui/server.js')
def copy_nni_node(version):
"""
Copy compiled JS files to nni_node.
This is meant for building release package, so you need to provide version string.
The version will written to `package.json` in nni_node directory,
while `package.json` in ts directory will be left unchanged.
"""
_print('Copying files')
clear_nni_node()
# copytree(..., dirs_exist_ok=True) is not supported by Python 3.6
for path in Path('ts/nni_manager/dist').iterdir():
if path.is_file():
shutil.copyfile(path, Path('nni_node', path.name))
else:
shutil.copytree(path, Path('nni_node', path.name))
package_json = json.load(open('ts/nni_manager/package.json'))
if version.count('.') == 1: # node.js semver requires at least three parts
version = version + '.0'
package_json['version'] = version
json.dump(package_json, open('nni_node/package.json', 'w'), indent=2)
_yarn('ts/nni_manager', '--prod', '--cwd', str(Path('nni_node').resolve()))
shutil.copytree('ts/webui/build', 'nni_node/static')
Path('nni_node/nasui').mkdir(exist_ok=True)
shutil.copytree('ts/nasui/build', 'nni_node/nasui/build')
shutil.copyfile('ts/nasui/server.js', 'nni_node/nasui/server.js')
def clear_nni_node():
"""
Remove compiled files in nni_node.
Use `clean()` if you what to remove files in ts as well.
"""
for path in Path('nni_node').iterdir():
if path.name not in ('__init__.py', 'node', 'node.exe'):
if path.is_symlink() or path.is_file():
path.unlink()
else:
shutil.rmtree(path)
_yarn_env = dict(os.environ)
_yarn_env['PATH'] = str(Path('nni_node').resolve()) + ':' + os.environ['PATH']
_yarn_path = Path('toolchain/yarn/bin', yarn_executable).resolve()
def _yarn(path, *args):
if os.environ.get('GLOBAL_TOOLCHAIN'):
subprocess.run(['yarn', *args], cwd=path, check=True)
else:
subprocess.run([_yarn_path, *args], cwd=path, check=True, env=_yarn_env)
def _symlink(target_file, link_location):
target = Path(target_file)
link = Path(link_location)
relative = os.path.relpath(target, link.parent)
link.symlink_to(relative, target.is_dir())
def _print(*args):
print('\033[1;36m# ', end='')
print(*args, end='')
print('\033[0m')
generated_directories = [
'ts/nni_manager/dist',
'ts/nni_manager/node_modules',
'ts/webui/build',
'ts/webui/node_modules',
'ts/nasui/build',
'ts/nasui/node_modules',
]
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
branch = True branch = True
parallel = True parallel = True
data_file = ${COVERAGE_DATA_FILE} data_file = ${COVERAGE_DATA_FILE}
source = nni, nni_cmd, nni_trial_tool source = nni, nni.tools.cmd, nni.tools.trial_tool
concurrency = multiprocessing concurrency = multiprocessing
......
...@@ -147,8 +147,8 @@ testCases: ...@@ -147,8 +147,8 @@ testCases:
config: config:
maxTrialNum: 4 maxTrialNum: 4
trialConcurrency: 4 trialConcurrency: 4
launchCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.start_experiment("$configFile")' launchCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.start_experiment("$configFile")'
stopCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()' stopCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()'
validator: validator:
class: NnicliValidator class: NnicliValidator
platform: linux darwin platform: linux darwin
......
...@@ -110,8 +110,8 @@ testCases: ...@@ -110,8 +110,8 @@ testCases:
config: config:
maxTrialNum: 4 maxTrialNum: 4
trialConcurrency: 4 trialConcurrency: 4
launchCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.start_experiment("$configFile")' launchCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.start_experiment("$configFile")'
stopCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()' stopCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()'
validator: validator:
class: NnicliValidator class: NnicliValidator
platform: linux darwin platform: linux darwin
......
...@@ -47,8 +47,8 @@ testCases: ...@@ -47,8 +47,8 @@ testCases:
config: config:
maxTrialNum: 4 maxTrialNum: 4
trialConcurrency: 4 trialConcurrency: 4
launchCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.start_experiment("$configFile")' launchCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.start_experiment("$configFile")'
stopCommand: python3 -c 'from nnicli import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()' stopCommand: python3 -c 'from nni.experiment import Experiment; exp = Experiment(); exp.connect_experiment("http://localhost:8080/"); exp.stop_experiment()'
validator: validator:
class: NnicliValidator class: NnicliValidator
platform: linux darwin platform: linux darwin
......
...@@ -6,8 +6,8 @@ from os import remove ...@@ -6,8 +6,8 @@ from os import remove
import subprocess import subprocess
import json import json
import requests import requests
from nnicli import Experiment from nni.experiment import Experiment
from nni_cmd.updater import load_search_space from nni.tools.nnictl.updater import load_search_space
from utils import METRICS_URL, GET_IMPORTED_DATA_URL from utils import METRICS_URL, GET_IMPORTED_DATA_URL
......
...@@ -7,8 +7,8 @@ CWD=${PWD} ...@@ -7,8 +7,8 @@ CWD=${PWD}
## ------Run annotation test------ ## ------Run annotation test------
echo "" echo ""
echo "===========================Testing: nni_annotation===========================" echo "===========================Testing: nni_annotation==========================="
cd ${CWD}/../tools/ #cd ${CWD}/../tools/
python3 -m unittest -v nni_annotation/test_annotation.py #python3 -m unittest -v nni_annotation/test_annotation.py
## Export certain environment variables for unittest code to work ## Export certain environment variables for unittest code to work
export NNI_TRIAL_JOB_ID=test_trial_job_id export NNI_TRIAL_JOB_ID=test_trial_job_id
...@@ -17,23 +17,23 @@ export NNI_PLATFORM=unittest ...@@ -17,23 +17,23 @@ export NNI_PLATFORM=unittest
## ------Run sdk test------ ## ------Run sdk test------
echo "" echo ""
echo "===========================Testing: nni_sdk===========================" echo "===========================Testing: nni_sdk==========================="
cd ${CWD}/../src/sdk/pynni/ #cd ${CWD}/../src/sdk/pynni/
python3 -m unittest discover -v tests #python3 -m unittest discover -v tests
# -------------For typescript unittest------------- # -------------For typescript unittest-------------
cd ${CWD}/../src/nni_manager #cd ${CWD}/../ts/nni_manager
echo "" echo ""
echo "===========================Testing: nni_manager===========================" echo "===========================Testing: nni_manager==========================="
npm run test #npm run test
# -------------For NASUI unittest------------- # -------------For NASUI unittest-------------
cd ${CWD}/../src/nasui #cd ${CWD}/../ts/nasui
echo "" echo ""
echo "===========================Testing: nasui===========================" echo "===========================Testing: nasui==========================="
CI=true npm test #CI=true npm test
## ------Run nnictl unit test------ ## ------Run nnictl unit test------
echo "" echo ""
echo "===========================Testing: nnictl===========================" echo "===========================Testing: nnictl==========================="
cd ${CWD}/../tools/nni_cmd/ #cd ${CWD}/../tools/nni_cmd/
python3 -m unittest discover -v tests #python3 -m unittest discover -v tests
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment