Unverified Commit 035d58bc authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #121 from Microsoft/master

merge master
parents b633c265 8e732f2c
......@@ -50,7 +50,7 @@ net = build_graph_from_json(RCV_CONFIG)
# training procedure
# ....
# report the final accuracy to nni
# report the final accuracy to NNI
nni.report_final_result(best_acc)
```
......
......@@ -36,7 +36,7 @@ if not os.path.exists(_outputdir):
os.makedirs(_outputdir)
_nni_platform = os.environ['NNI_PLATFORM']
if _nni_platform not in ['pai', 'kubeflow', 'frameworkcontroller']:
if _nni_platform == 'local':
_log_file_path = os.path.join(_outputdir, 'trial.log')
init_logger(_log_file_path)
......@@ -69,7 +69,7 @@ def get_next_parameter():
params_filepath = os.path.join(_sysdir, params_file_name)
if not os.path.isfile(params_filepath):
request_next_parameter()
while not os.path.isfile(params_filepath):
while not (os.path.isfile(params_filepath) and os.path.getsize(params_filepath) > 0):
time.sleep(3)
params_file = open(params_filepath, 'r')
params = json.load(params_file)
......@@ -77,7 +77,7 @@ def get_next_parameter():
return params
def send_metric(string):
if _nni_platform in ['pai', 'kubeflow', 'frameworkcontroller']:
if _nni_platform != 'local':
data = (string).encode('utf8')
assert len(data) < 1000000, 'Metric too long'
print('NNISDK_ME%s' % (data))
......
# Integration doc: SMAC on nni
\ No newline at end of file
# Integration doc: SMAC on NNI
\ No newline at end of file
......@@ -41,6 +41,7 @@ def generate_pcs(nni_search_space_content):
# parameter_name real [min_value, max_value] [default value] log
# https://automl.github.io/SMAC3/stable/options.html
'''
categorical_dict = {}
search_space = nni_search_space_content
with open('param_config_space.pcs', 'w') as pcs_fd:
if isinstance(search_space, dict):
......@@ -48,10 +49,14 @@ def generate_pcs(nni_search_space_content):
if isinstance(search_space[key], dict):
try:
if search_space[key]['_type'] == 'choice':
choice_len = len(search_space[key]['_value'])
pcs_fd.write('%s categorical {%s} [%s]\n' % (
key,
json.dumps(search_space[key]['_value'])[1:-1],
json.dumps(search_space[key]['_value'][0])))
json.dumps(list(range(choice_len)))[1:-1],
json.dumps(0)))
if key in categorical_dict:
raise RuntimeError('%s has already existed, please make sure search space has no duplicate key.' % key)
categorical_dict[key] = search_space[key]['_value']
elif search_space[key]['_type'] == 'randint':
# TODO: support lower bound in randint
pcs_fd.write('%s integer [0, %d] [%d]\n' % (
......@@ -83,6 +88,8 @@ def generate_pcs(nni_search_space_content):
raise RuntimeError('_type or _value error.')
else:
raise RuntimeError('incorrect search space.')
return categorical_dict
return None
def generate_scenario(ss_content):
'''
......@@ -119,7 +126,7 @@ def generate_scenario(ss_content):
sce_fd.write('paramfile = param_config_space.pcs\n')
sce_fd.write('run_obj = quality\n')
generate_pcs(ss_content)
return generate_pcs(ss_content)
if __name__ == '__main__':
generate_scenario('search_space.json')
......@@ -58,6 +58,7 @@ class SMACTuner(Tuner):
self.first_one = True
self.update_ss_done = False
self.loguniform_key = set()
self.categorical_dict = {}
def _main_cli(self):
'''
......@@ -128,7 +129,9 @@ class SMACTuner(Tuner):
NOTE: updating search space is not supported.
'''
if not self.update_ss_done:
generate_scenario(search_space)
self.categorical_dict = generate_scenario(search_space)
if self.categorical_dict is None:
raise RuntimeError('categorical dict is not correctly returned after parsing search space.')
self.optimizer = self._main_cli()
self.smbo_solver = self.optimizer.solver
self.loguniform_key = {key for key in search_space.keys() if search_space[key]['_type'] == 'loguniform'}
......@@ -152,13 +155,21 @@ class SMACTuner(Tuner):
else:
self.smbo_solver.nni_smac_receive_runs(self.total_data[parameter_id], reward)
def convert_loguniform(self, challenger_dict):
def convert_loguniform_categorical(self, challenger_dict):
'''
convert the values of type `loguniform` back to their initial range
Convert the values of type `loguniform` back to their initial range
Also, we convert categorical:
categorical values in search space are changed to list of numbers before,
those original values will be changed back in this function
'''
for key, value in challenger_dict.items():
# convert to loguniform
if key in self.loguniform_key:
challenger_dict[key] = np.exp(challenger_dict[key])
# convert categorical back to original value
if key in self.categorical_dict:
idx = challenger_dict[key]
challenger_dict[key] = self.categorical_dict[key][idx]
return challenger_dict
def generate_parameters(self, parameter_id):
......@@ -169,13 +180,13 @@ class SMACTuner(Tuner):
init_challenger = self.smbo_solver.nni_smac_start()
self.total_data[parameter_id] = init_challenger
json_tricks.dumps(init_challenger.get_dictionary())
return self.convert_loguniform(init_challenger.get_dictionary())
return self.convert_loguniform_categorical(init_challenger.get_dictionary())
else:
challengers = self.smbo_solver.nni_smac_request_challengers()
for challenger in challengers:
self.total_data[parameter_id] = challenger
json_tricks.dumps(challenger.get_dictionary())
return self.convert_loguniform(challenger.get_dictionary())
return self.convert_loguniform_categorical(challenger.get_dictionary())
def generate_multiple_parameters(self, parameter_id_list):
'''
......@@ -189,7 +200,7 @@ class SMACTuner(Tuner):
init_challenger = self.smbo_solver.nni_smac_start()
self.total_data[one_id] = init_challenger
json_tricks.dumps(init_challenger.get_dictionary())
params.append(self.convert_loguniform(init_challenger.get_dictionary()))
params.append(self.convert_loguniform_categorical(init_challenger.get_dictionary()))
else:
challengers = self.smbo_solver.nni_smac_request_challengers()
cnt = 0
......@@ -199,6 +210,6 @@ class SMACTuner(Tuner):
break
self.total_data[parameter_id_list[cnt]] = challenger
json_tricks.dumps(challenger.get_dictionary())
params.append(self.convert_loguniform(challenger.get_dictionary()))
params.append(self.convert_loguniform_categorical(challenger.get_dictionary()))
cnt += 1
return params
......@@ -221,7 +221,7 @@ class SlideBar extends React.Component<{}, SliderState> {
Download <Icon type="down" />
</a>
</Dropdown>
<a href="https://github.com/Microsoft/nni/issues/new?labels=v0.5" target="_blank">
<a href="https://github.com/Microsoft/nni/issues/new?labels=v0.5.1" target="_blank">
<img
src={require('../static/img/icon/issue.png')}
alt="NNI github issue"
......
......@@ -57,8 +57,7 @@ class OpenRow extends React.Component<OpenRowProps, {}> {
</TabPane>
<TabPane tab="Log" key="2">
{
trainingPlatform === 'pai' || trainingPlatform === 'kubeflow' ||
trainingPlatform === 'frameworkcontroller'
trainingPlatform !== 'local'
?
<PaiTrialLog
logStr={logPathRow}
......
authorName: nni
experimentName: default_test
maxExecDuration: 15m
maxTrialNum: 4
maxTrialNum: 2
trialConcurrency: 2
searchSpacePath: ./cifar10_search_space.json
......
authorName: nni
experimentName: default_test
maxExecDuration: 5m
maxTrialNum: 2
trialConcurrency: 2
maxTrialNum: 16
trialConcurrency: 8
searchSpacePath: ./search_space.json
tuner:
......
......@@ -106,7 +106,7 @@ def start_rest_server(port, platform, mode, config_file_name, experiment_id=None
'You could use \'nnictl create --help\' to get help information' % port)
exit(1)
if (platform == 'pai' or platform == 'kubeflow') and detect_port(int(port) + 1):
if (platform != 'local') and detect_port(int(port) + 1):
print_error('PAI mode need an additional adjacent port %d, and the port %d is used by another process!\n' \
'You could set another port to start experiment!\n' \
'You could use \'nnictl create --help\' to get help information' % ((int(port) + 1), (int(port) + 1)))
......
......@@ -25,7 +25,7 @@ import time
from xml.dom import minidom
def check_ready_to_run():
pgrep_output =subprocess.check_output('pgrep -fx \'python3 gpu_metrics_collector.py\'', shell=True)
pgrep_output =subprocess.check_output('pgrep -fx \'python3 -m nni_gpu_tool.gpu_metrics_collector\'', shell=True)
pidList = []
for pid in pgrep_output.splitlines():
pidList.append(int(pid))
......@@ -33,17 +33,18 @@ def check_ready_to_run():
return len(pidList) == 0
def main(argv):
metrics_output_dir = os.environ['METRIC_OUTPUT_DIR']
if check_ready_to_run() == False:
# GPU metrics collector is already running. Exit
exit(2)
with open("./gpu_metrics", "w") as outputFile:
with open(os.path.join(metrics_output_dir, "gpu_metrics"), "w") as outputFile:
pass
os.chmod("./gpu_metrics", 0o777)
os.chmod(os.path.join(metrics_output_dir, "gpu_metrics"), 0o777)
cmd = 'nvidia-smi -q -x'
while(True):
try:
smi_output = subprocess.check_output(cmd, shell=True)
parse_nvidia_smi_result(smi_output, '.')
parse_nvidia_smi_result(smi_output, metrics_output_dir)
except:
exception = sys.exc_info()
for e in exception:
......
# Makefile 文件和安装配置
NNI 使用 GNU 来生成和安装。
`Makefile` 提供标准的目标 `生成``安装``卸载`, 以及不同设置的安装对象:
* `easy-install`: 针对非专家用户,自动处理所有内容;
* `dev-easy-install`: 针对专家用户,自动处理所有内容;
* `install`: 针对 NNI 普通用户,通过复制文件来安装 NNI;
* `dev-install`: 针对 NNI 贡献者,通过创建 symlinks 而不是复制文件来安装 NNI;
* `pip-install`: 针对使用 `setup.py` 安装的情况;
下文会有更详细的介绍。
## 依赖项
NNI 依赖于 Node.js, Yarn, 和 pip 来生成,推荐安装 TypeScript。
NNI 需要 Node.js 以及运行所需要的所有库。 需要的 Node.js 库 (包括 TypeScript) 可以通过 Yarn 来安装, 需要的 Python 库可以通过 setuptools 或者 PIP 来安装。
NNI *用户*可以用 `make install-dependencies` 来安装 Node.js 和 Yarn。 Node.js 会被安装到 NNI 的安装目录,Yarn 会被安装到 `/tmp/nni-yarn`。 安装过程需要 wget。
NNI *开发人员*推荐手工安装 Node.js 和 Yarn。 可浏览相应的官方文档了解安装过程。
## 生成 NNI
当依赖项安装好后,运行 `make` 即可。
## 安装
### 目录层次
NNI 项目主要由两个 Node.js 模块 (`nni_manager`, `webui`) 以及两个 Python 包 (`nni`, `nnictl`) 所组成。
默认情况下,Node.js 模块可以为所有用户安装在 `/usr/share/nni` 目录下,也可为只安装在当前用户的 `~/.local/nni` 目录下。
Python 包使用 setuptools 安装,所以安装路径依赖于 Python 配置。 如果为没有权限的用户安装,并且没有虚拟环境的时候,要加上 `--user` 参数。
此外,`nnictl` 是一个 bash 脚本,会被安装在 `/usr/share/bash-completion/completions``~/.bash_completion.d` 目录下。
在某些配置情况下,NNI 也会将 Node.js 安装到 `/usr/share/nni` 目录下。
以上所有目录都可以配置。 可参考下一章节。
### 配置
`Makefile` 中可以用环境变量来替换默认设置。
支持的变量如下:
| 名称 | 说明 | 普通用户下的默认值 | root 下的默认值 |
| ------------------ | ------------------------------ | ---------------------------------- | ----------------------------------------------- |
| `BIN_PATH` | 执行文件路径 | `~/.local/bin` | `/usr/bin` |
| `INSTALL_PREFIX` | Node.js 模块的路径 (最后会加上 `nni`) | `~/.local` | `/usr/share` |
| `BASH_COMP_SCRIPT` | Bash 自动完成脚本的路径 | `~/.bash_completion.d/nnictl` | `/usr/share/bash-completion/completions/nnictl` |
| `PIP_MODE` | `python3 setup.py install` 的参数 | 如果 `VIRTUAL_ENV` 没有设置,会加上 `--user` | (无) |
| `NODE_PATH` | Node.js 运行时的路径 | `$INSTALL_PREFIX/nni/node` | `$INSTALL_PREFIX/nni/node` |
| `YARN_PATH` | Yarn 的安装路径 | `/tmp/nni-yarn` | `/tmp/nni-yarn` |
| `NODE` | Node.js 命令 | 参考源代码 | 参考源代码 |
| `YARN` | Yarn 命令 | 参考源代码 | 参考源代码 |
注意,这些变量不仅会影响安装路径,也会影响申城的 `nnictl``nnimanager` 脚本。 如果复制文件的路径和运行时的不一样(例如,创建发行版本包时),需要手工编辑 `nnictl``nnimanager`
### 目标
安装目标的流程如下:
| 目标 | 流程 |
| ------------------ | ------------------------------------------------ |
| `easy-install` | 安装依赖项,生成,安装 NNI,并编辑 `~/.bashrc` |
| `dev-easy-install` | 安装依赖项,生成,将 NNI 作为 symlinks 来安装,并编辑 `~/.bashrc` |
| `install` | 安装 Python 包,Node.js 模块,NNI 脚本和样例 |
| `dev-install` | 将 Python 和 Node.js 模块作为 symlinks 安装,然后安装 scripts |
| `pip-install` | 安装依赖项,生成,安装 NNI,但不安装 Python 包 |
## TODO
* `clean` 目标
* `test` 目标
* `lint` 目标
* 每个目标的测试用例
* 评审变量
\ No newline at end of file
<p align="center">
<img src="https://microsoft.github.io/nni/docs/img/nni_logo.png" width="300"/>
</p>
* * *
[![MIT 许可证](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/Microsoft/nni/blob/master/LICENSE) [![生成状态](https://msrasrg.visualstudio.com/NNIOpenSource/_apis/build/status/Microsoft.nni)](https://msrasrg.visualstudio.com/NNIOpenSource/_build/latest?definitionId=6) [![问题](https://img.shields.io/github/issues-raw/Microsoft/nni.svg)](https://github.com/Microsoft/nni/issues?q=is%3Aissue+is%3Aopen) [![Bug](https://img.shields.io/github/issues/Microsoft/nni/bug.svg)](https://github.com/Microsoft/nni/issues?q=is%3Aissue+is%3Aopen+label%3Abug) [![拉取请求](https://img.shields.io/github/issues-pr-raw/Microsoft/nni.svg)](https://github.com/Microsoft/nni/pulls?q=is%3Apr+is%3Aopen) [![版本](https://img.shields.io/github/release/Microsoft/nni.svg)](https://github.com/Microsoft/nni/releases) [![进入 https://gitter.im/Microsoft/nni 聊天室提问](https://badges.gitter.im/Microsoft/nni.svg)](https://gitter.im/Microsoft/nni?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[English](../README.md)
NNI (Neural Network Intelligence) 是自动机器学习(AutoML)的工具包。 它通过多种调优的算法来搜索最好的神经网络结构和(或)超参,并支持单机、本地多机、云等不同的运行环境。
### **NNI [v0.5.1](https://github.com/Microsoft/nni/releases) 已发布!**
<p align="center">
<a href="#nni-v05-has-been-released"><img src="https://microsoft.github.io/nni/docs/img/overview.svg" /></a>
</p>
<table>
<tbody>
<tr align="center" valign="bottom">
<td>
<b>支持的框架</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
</td>
<td>
<b>调优算法</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
</td>
<td>
<b>训练服务</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
</td>
</tr>
<tr/>
<tr valign="top">
<td>
<ul>
<li>PyTorch</li>
<li>TensorFlow</li>
<li>Keras</li>
<li>MXNet</li>
<li>Caffe2</li>
<li>CNTK (Python 语言)</li>
<li>Chainer</li>
<li>Theano</li>
</ul>
</td>
<td>
<a href="docs/Builtin_Tuner.md">Tuner(调参器)</a>
<ul>
<li><a href="docs/Builtin_Tuner.md#TPE">TPE</a></li>
<li><a href="docs/Builtin_Tuner.md#Random">Random Search(随机搜索)</a></li>
<li><a href="docs/Builtin_Tuner.md#Anneal">Anneal(退火算法)</a></li>
<li><a href="docs/Builtin_Tuner.md#Evolution">Naive Evolution(进化算法)</a></li>
<li><a href="docs/Builtin_Tuner.md#SMAC">SMAC</a></li>
<li><a href="docs/Builtin_Tuner.md#Batch">Batch(批处理)</a></li>
<li><a href="docs/Builtin_Tuner.md#Grid">Grid Search(遍历搜索)</a></li>
<li><a href="docs/Builtin_Tuner.md#Hyperband">Hyperband</a></li>
<li><a href="docs/Builtin_Tuner.md#NetworkMorphism">Network Morphism</a></li>
<li><a href="examples/tuners/enas_nni/README.md">ENAS</a></li>
<li><a href="docs/Builtin_Tuner.md#NetworkMorphism#MetisTuner">Metis Tuner</a></li>
</ul>
<a href="docs/Builtin_Tuner.md#assessor">Assessor(评估器)</a>
<ul>
<li><a href="docs/Builtin_Tuner.md#Medianstop">Median Stop</a></li>
<li><a href="docs/Builtin_Tuner.md#Curvefitting">Curve Fitting</a></li>
</ul>
</td>
<td>
<ul>
<li><a href="docs/tutorial_1_CR_exp_local_api.md">本地计算机</a></li>
<li><a href="docs/RemoteMachineMode.md">远程计算机</a></li>
<li><a href="docs/PAIMode.md">OpenPAI</a></li>
<li><a href="docs/KubeflowMode.md">Kubeflow</a></li>
<li><a href="docs/FrameworkControllerMode.md">基于 Kubernetes(AKS 等等)的 FrameworkController</a></li>
</ul>
</td>
</tr>
</tbody>
</table>
## **使用场景**
* 在本地 Trial 不同的自动机器学习算法来训练模型。
* 在分布式环境中加速自动机器学习(如:远程 GPU 工作站和云服务器)。
* 定制自动机器学习算法,或比较不同的自动机器学习算法。
* 在自己的机器学习平台中支持自动机器学习。
## 相关项目
以开发和先进技术为目标,[Microsoft Research (MSR)](https://www.microsoft.com/en-us/research/group/systems-research-group-asia/) 发布了一些开源项目。
* [OpenPAI](https://github.com/Microsoft/pai):作为开源平台,提供了完整的 AI 模型训练和资源管理能力,能轻松扩展,并支持各种规模的私有部署、云和混合环境。
* [FrameworkController](https://github.com/Microsoft/frameworkcontroller):开源的通用 Kubernetes Pod 控制器,通过单个控制器来编排 Kubernetes 上所有类型的应用。
* [MMdnn](https://github.com/Microsoft/MMdnn):一个完成、跨框架的解决方案,能够转换、可视化、诊断深度神经网络模型。 MMdnn 中的 "MM" 表示model management(模型管理),而 "dnn" 是 deep neural network(深度神经网络)的缩写。 我们鼓励研究人员和学生利用这些项目来加速 AI 开发和研究。
## **安装和验证**
**通过 pip 命令安装**
* 当前支持 Linux 和 MacOS。测试并支持的版本包括:Ubuntu 16.04 及更高版本,MacOS 10.14.1。 在 `python >= 3.5` 的环境中,只需要运行 `pip install` 即可完成安装。
```bash
python3 -m pip install --upgrade nni
```
注意:
* 如果需要将 NNI 安装到自己的 home 目录中,可使用 `--user`,这样也不需要任何特殊权限。
* 如果遇到如`Segmentation fault` 这样的任何错误请参考[常见问题](docs/FAQ.md)
**通过源代码安装**
* 当前支持 Linux(Ubuntu 16.04 及更高版本) 和 MacOS(10.14.1)。
*`python >= 3.5` 的环境中运行命令: `git``wget`,确保安装了这两个组件。
```bash
git clone -b v0.5.1 https://github.com/Microsoft/nni.git
cd nni
source install.sh
```
参考[安装 NNI](docs/Installation.md) 了解系统需求。
**验证安装**
以下示例 Experiment 依赖于 TensorFlow 。 在运行前确保安装了 **TensorFlow**
* 通过克隆源代码下载示例。
```bash
git clone -b v0.5.1 https://github.com/Microsoft/nni.git
```
* 运行 mnist 示例。
```bash
nnictl create --config nni/examples/trials/mnist/config.yml
```
* 在命令行中等待输出 `INFO: Successfully started experiment!`。 此消息表明 Experiment 已成功启动。 通过命令行输出的 `Web UI url` 来访问 Experiment 的界面。
```
INFO: Starting restful server...
INFO: Successfully started Restful server!
INFO: Setting local config...
INFO: Successfully set local config!
INFO: Starting experiment...
INFO: Successfully started experiment!
-----------------------------------------------------------------------
The experiment id is egchD4qy
The Web UI urls are: http://223.255.255.1:8080 http://127.0.0.1:8080
-----------------------------------------------------------------------
You can use these commands to get more information about the experiment
-----------------------------------------------------------------------
commands description
1. nnictl experiment show show the information of experiments
2. nnictl trial ls list all of trial jobs
3. nnictl top monitor the status of running experiments
4. nnictl log stderr show stderr log content
5. nnictl log stdout show stdout log content
6. nnictl stop stop an experiment
7. nnictl trial kill kill a trial job by id
8. nnictl --help get help information about nnictl
-----------------------------------------------------------------------
* 在浏览器中打开 `Web UI url`,可看到下图的 Experiment 详细信息,以及所有的 Trial 任务。 查看[这里的](docs/WebUI.md)更多页面示例。
<table style="border: none">
<th><img src="./docs/img/webui_overview_page.png" alt="drawing" width="395"/></th>
<th><img src="./docs/img/webui_trialdetail_page.png" alt="drawing" width="410"/></th>
</table>
## **文档**
* [NNI 概述](docs/Overview.md)
* [快速入门](docs/QuickStart.md)
## **入门**
* [安装 NNI](docs/Installation.md)
* [使用命令行工具 nnictl](docs/NNICTLDOC.md)
* [使用 NNIBoard](docs/WebUI.md)
* [如何定义搜索空间](docs/SearchSpaceSpec.md)
* [如何定义一次 Trial](docs/Trials.md)
* [如何选择 Tuner、搜索算法](docs/Builtin_Tuner.md)
* [配置 Experiment](docs/ExperimentConfig.md)
* [如何使用 Annotation](docs/Trials.md#nni-python-annotation)
## **教程**
* [在本机运行 Experiment (支持多 GPU 卡)](docs/tutorial_1_CR_exp_local_api.md)
* [在多机上运行 Experiment](docs/RemoteMachineMode.md)
* [在 OpenPAI 上运行 Experiment](docs/PAIMode.md)
* [在 Kubeflow 上运行 Experiment。](docs/KubeflowMode.md)
* [尝试不同的 Tuner](docs/tuners.rst)
* [尝试不同的 Assessor](docs/assessors.rst)
* [实现自定义 Tuner](docs/Customize_Tuner.md)
* [实现自定义 Assessor](examples/assessors/README.md)
* [使用进化算法为阅读理解任务找到好模型](examples/trials/ga_squad/README.md)
## **贡献**
欢迎贡献代码或提交建议,可在 [GitHub issues](https://github.com/Microsoft/nni/issues) 跟踪需求和 Bug。
推荐新贡献者从标有 **good first issue** 的简单需求开始。
如要安装 NNI 开发环境,参考: [配置 NNI 开发环境](docs/SetupNNIDeveloperEnvironment.md)
在写代码之前,请查看并熟悉 NNI 代码贡献指南:[贡献](docs/CONTRIBUTING.md)
我们正在编写 [如何调试](docs/HowToDebug.md) 的页面,欢迎提交建议和问题。
## **许可协议**
代码库遵循 [MIT 许可协议](https://github.com/Microsoft/nni/blob/master/LICENSE)
\ No newline at end of file
# Dockerfile
## 1. 说明
这是 NNI 项目的 Dockerfile 文件。 其中包含了 NNI 以及多个流行的深度学习框架。 在 `Ubuntu 16.04 LTS` 上进行过测试:
CUDA 9.0, CuDNN 7.0
numpy 1.14.3,scipy 1.1.0
TensorFlow-gpu 1.10.0
Keras 2.1.6
PyTorch 0.4.1
scikit-learn 0.20.0
pandas 0.23.4
lightgbm 2.2.2
NNI v0.5.1
此 Dockerfile 可作为定制的参考。
## 2.如何生成和运行
**使用 `nni/deployment/docker` 的下列命令来生成 docker 映像。**
docker build -t nni/nni .
**运行 docker 映像**
* 如果 docker 容器中没有 GPU,运行下面的命令
docker run -it nni/nni
注意,如果要使用 tensorflow,需要先卸载 tensorflow-gpu,然后在 Docker 容器中安装 tensorflow。 或者修改 `Dockerfile` 来安装没有 GPU 的 tensorflow 版本,并重新生成 Docker 映像。
* 如果 docker 容器中有 GPU,确保安装了 [NVIDIA 容器运行包](https://github.com/NVIDIA/nvidia-docker),然后运行下面的命令
nvidia-docker run -it nni/nni
或者
docker run --runtime=nvidia -it nni/nni
## 3.拉取 docker 映像
使用下列命令从 docker Hub 中拉取 NNI docker 映像。
docker pull msranni/nni:latest
\ No newline at end of file
# 用于 NNI 的 python 包索引 (pypi)
## 1. 说明
这是用于 NNI 项目的 PyPI 生成和上传的工具。
## 2.准备环境
在生成和上传 NNI 包之前,确保使用了下列环境。
Ubuntu 16.04 LTS
make
wget
Python >= 3.5
Pip
Node.js
Yarn
## 2.如何生成
```bash
make
```
## 3.如何上传
### 上传测试包
```bash
TWINE_REPOSITORY_URL=https://test.pypi.org/legacy/ make upload
```
上传过程中,可能需要输入 https://test.pypi.org 的用户和密码。
### 上传发布包
```bash
make upload
```
上传过程中,可能需要输入 https://pypi.org 的用户和密码。
\ No newline at end of file
_build
_static
_templates
\ No newline at end of file
# 高级神经网络架构搜索教程
目前,许多 NAS(Neural Architecture Search,神经网络架构搜索)算法都在 Trial 上使用了 **权重共享(weight sharing)** 的方法来加速训练过程。 例如,[ENAS](https://arxiv.org/abs/1802.03268) 与以前的 [NASNet](https://arxiv.org/abs/1707.07012) 算法相比,通过'*子模型间的参数共享(parameter sharing between child models)*'提高了 1000 倍的效率。 而例如 [DARTS](https://arxiv.org/abs/1806.09055), [Network Morphism](https://arxiv.org/abs/1806.10282), 和 [Evolution](https://arxiv.org/abs/1703.01041) 等算法也利用或者隐式的利用了权重共享。
本教程介绍了如何使用权重共享。
## 权重共享
推荐通过 NFS (Network File System)进行权重共享,它是轻量、相对高效的多机共享文件方案。 欢迎社区来共享更多高效的技术。
### 通过 NFS 文件使用权重共享
使用 NFS 配置(见下文),Trial 代码可以通过读写文件来共享模型权重。 建议使用 Tuner 的存储路径:
```yaml
tuner:
codeDir: path/to/customer_tuner
classFileName: customer_tuner.py
className: CustomerTuner
classArgs:
...
save_dir_root: /nfs/storage/path/
```
并让 Tuner 来决定在什么路径读写权重文件,通过 `nni.get_next_parameters()` 来获取路径:
<img src="https://user-images.githubusercontent.com/23273522/51817667-93ebf080-2306-11e9-8395-b18b322062bc.png" alt="drawing" width="700" />
例如,在 Tensorflow 中:
```python
# 保存 models
saver = tf.train.Saver()
saver.save(sess, os.path.join(params['save_path'], 'model.ckpt'))
# 读取 models
tf.init_from_checkpoint(params['restore_path'])
```
超参中的 `'save_path'``'restore_path'` 可以通过 Tuner 来管理。
### NFS 配置
NFS 使用了客户端/服务器架构。通过一个 NFS 服务器来提供物理存储,远程计算机上的 Trial 使用 NFS 客户端来读写文件,操作上和本地文件相同。
#### NFS 服务器
如果有足够的存储空间,并能够让 NNI 的 Trial 通过**远程机器**来连接,NFS 服务可以安装在任何计算机上。 通常,可以选择一台远程服务器作为 NFS 服务。
在 Ubuntu 上,可通过 `apt-get` 安装 NFS 服务:
```bash
sudo apt-get install nfs-kernel-server
```
假设 `/tmp/nni/shared` 是物理存储位置,然后运行:
```bash
mkdir -p /tmp/nni/shared
sudo echo "/tmp/nni/shared *(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
sudo service nfs-kernel-server restart
```
可以通过命令 `sudo showmount -e localhost` 来检查上述目录是否通过 NFS 成功导出了
#### NFS 客户端
为了通过 NFS 访问远程共享文件,需要安装 NFS 客户端。 例如,在 Ubuntu 上运行:
```bash
sudo apt-get install nfs-common
```
然后创建并装载上共享目录:
```bash
mkdir -p /mnt/nfs/nni/
sudo mount -t nfs 10.10.10.10:/tmp/nni/shared /mnt/nfs/nni
```
实际使用时,IP `10.10.10.10` 需要替换为 NFS 服务器的真实地址。
## Trial 依赖控制的异步调度模式
多机间启用权重的 Trial,一般是通过**先写后读**的方式来保持一致性。 子节点在父节点的 Trial 完成训练前,不应该读取父节点模型。 要解决这个问题,要通过 `multiThread: true` 来启用**异步调度模式**。在 `config.yml` 中,每次收到 `NEW_TRIAL` 请求,分派一个新的 Trial 时,Tuner 线程可以决定是否阻塞当前线程。 例如:
```python
def generate_parameters(self, parameter_id):
self.thread_lock.acquire()
indiv = # 新 Trial 的配置
self.events[parameter_id] = threading.Event()
self.thread_lock.release()
if indiv.parent_id is not None:
self.events[indiv.parent_id].wait()
def receive_trial_result(self, parameter_id, parameters, reward):
self.thread_lock.acquire()
# 处理 Trial 结果的配置
self.thread_lock.release()
self.events[parameter_id].set()
```
## 样例
详细内容参考:[简单的参数共享样例](https://github.com/Microsoft/nni/tree/master/test/async_sharing_test)。 基于上一个 [ga_squad](https://github.com/Microsoft/nni/tree/master/examples/trials/ga_squad) 样例,还提供了新的 [样例](https://github.com/Microsoft/nni/tree/master/examples/trials/weight_sharing/ga_squad)
\ No newline at end of file
# NNI Annotation
## 概述
为了获得良好的用户体验并减少对以后代码的影响,NNI 设计了通过 Annotation(标记)来使用的语法。 通过 Annotation,只需要在代码中加入一些注释字符串,就能启用 NNI,完全不影响代码原先的执行逻辑。
样例如下:
```python
'''@nni.variable(nni.choice(0.1, 0.01, 0.001), name=learning_rate)'''
learning_rate = 0.1
```
此样例中,NNI 会从 (0.1, 0.01, 0.001) 中选择一个值赋给 learning_rate 变量。 第一行就是 NNI 的 Annotation,是 Python 中的一个字符串。 接下来的一行需要是赋值语句。 NNI 会根据 Annotation 行的信息,来给这一行的变量赋上相应的值。
通过这种方式,不需要修改任何代码,代码既可以直接运行,又可以使用 NNI 来调参。
## Annotation 的类型:
NNI 中,有 4 种类型的 Annotation;
### 1. 变量
`'''@nni.variable(sampling_algo, name)'''`
`@nni.variable` 用来标记变量。
**参数**
- **sampling_algo**: 指定搜索空间的采样算法。 可将其换成 NNI 支持的其它采样函数,函数要以 `nni.` 开头。例如,`choice``uniform`,详见 [SearchSpaceSpec](SearchSpaceSpec.md)
- **name**: 将被赋值的变量名称。 注意,此参数应该与下面一行等号左边的值相同。
例如:
```python
'''@nni.variable(nni.choice(0.1, 0.01, 0.001), name=learning_rate)'''
learning_rate = 0.1
```
### 2. 函数
`'''@nni.function_choice(*functions, name)'''`
`@nni.function_choice` 可以从几个函数中选择一个来执行。
**参数**
- **\*functions**: 可选择的函数。 注意,必须是包括参数的完整函数调用。 例如 `max_pool(hidden_layer, pool_size)`
- **name**: 将被替换的函数名称。
例如:
```python
"""@nni.function_choice(max_pool(hidden_layer, pool_size), avg_pool(hidden_layer, pool_size), name=max_pool)"""
h_pooling = max_pool(hidden_layer, pool_size)
```
### 3. 中间结果
`'''@nni.report_intermediate_result(metrics)'''`
`@nni.report_intermediate_result` 用来返回中间结果,这和 <Trials.md> 中的 `nni.report_intermediate_result` 用法一样。
### 4. 最终结果
`'''@nni.report_final_result(metrics)'''`
`@nni.report_final_result` 用来返回当前 Trial 的最终结果,这和 <Trials.md> 中的 `nni.report_final_result` 用法一样。
\ No newline at end of file
# 内置 Assessor
NNI 提供了先进的调优算法,使用上也很简单。 下面是内置 Assessor 的介绍:
| Assessor | 算法简介 |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Medianstop** [(用法)](#MedianStop) | Medianstop 是一种简单的提前终止策略,可参考[论文](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/46180.pdf)。 如果 Trial X 的在步骤 S 的最好目标值比所有已完成 Trial 的步骤 S 的中位数值明显要低,就会停止运行 Trial X。 |
| [Curvefitting](../src/sdk/pynni/nni/curvefitting_assessor/README.md) [(用法)](#Curvefitting) | Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学习、预测、评估) 的算法。 如果预测的 Trial X 在 step S 比性能最好的 Trial要差,就会提前终止它。 此算法中采用了 12 种曲线来拟合精度。 |
## 用法
要使用 NNI 内置的 Assessor,需要在 `config.yml` 文件中添加 **builtinAssessorName****classArgs**。 这一节会介绍推荐的场景、参数等详细用法以及样例。
注意:参考样例中的格式来创建新的 `config.yml` 文件。
<a name="MedianStop"></a>
![](https://placehold.it/15/1589F0/000000?text=+) `Median Stop Assessor`
> 名称:**Medianstop**
**建议场景**
适用于各种性能曲线,可用到各种场景中来加速优化过程。
**参数**
* **optimize_mode** (*maximize 或 minimize, 可选, 默认值为 maximize*) - 如果为 'maximize', Assessor 会在结果小于期望值时**终止** Trial。 如果为 'minimize',Assessor 会在结果大于期望值时**终止** Trial。
* **start_step** (*int, 可选, 默认值为 0*) - 只有收到 start_step 个中间结果后,才开始判断是否一个 Trial 应该被终止。
**使用样例:**
```yaml
# config.yml
assessor:
builtinAssessorName: Medianstop
classArgs:
optimize_mode: maximize
start_step: 5
```
<br />
<a name="Curvefitting"></a>
![](https://placehold.it/15/1589F0/000000?text=+) `Curve Fitting Assessor`
> 名称:**Curvefitting**
**建议场景**
适用于各种性能曲线,可用到各种场景中来加速优化过程。 更好的是,它能够处理并评估性能类似的曲线。
**参数**
* **epoch_num** (*int, **必需***) - epoch 的总数。 需要此数据来决定需要预测点的总数。
* **optimize_mode** (*maximize 或 minimize, 可选, 默认值为 maximize*) - 如果为 'maximize', Assessor 会在结果小于期望值时**终止** Trial。 如果为 'minimize',Assessor 会在结果大于期望值时**终止** Trial。
* **start_step** (*int, 可选, 默认值为 6*) - 只有收到 start_step 个中间结果后,才开始判断是否一个 Trial 应该被终止。
* **threshold** (*float, 可选, 默认值为 0.95*) - 用来确定提前终止较差结果的阈值。 例如,如果 threshold = 0.95, optimize_mode = maximize,最好的历史结果是 0.9,那么会在 Trial 的预测值低于 0.95 * 0.9 = 0.855 时停止。
**使用样例:**
```yaml
# config.yml
assessor:
builtinAssessorName: Curvefitting
classArgs:
epoch_num: 20
optimize_mode: maximize
start_step: 6
threshold: 0.95
```
\ No newline at end of file
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