"src/targets/gpu/vscode:/vscode.git/clone" did not exist on "d7b1895adc24ba9989314c4146d1f5f7ca83d10c"
Commit 252f36f8 authored by Deshui Yu's avatar Deshui Yu
Browse files

NNI dogfood version 1

parent 781cea26
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import json
import os
from ..common import init_logger
_dir = os.environ['NNI_SYS_DIR']
_metric_file = open(os.path.join(_dir, '.nni', 'metrics'), 'wb')
_log_file_path = os.path.join(_dir, '.nni', 'trial.log')
init_logger(_log_file_path)
def get_parameters():
params_file = open(os.path.join(_dir, 'parameter.cfg'), 'r')
return json.load(params_file)
def send_metric(string):
data = (string + '\n').encode('utf8')
assert len(data) < 1000000, 'Metric too long'
_metric_file.write(b'ME%06d%b' % (len(data), data))
_metric_file.flush()
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import json_tricks
def get_parameters():
pass
def send_metric(string):
metric = json_tricks.loads(string)
if metric['type'] == 'FINAL':
print('Final result:', metric['value'])
elif metric['type'] == 'PERIODICAL':
print('Intermediate result:', metric['value'])
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
# pylint: skip-file
import copy
import json_tricks
_params = None
_last_metric = None
def get_parameters():
return _params
def send_metric(string):
global _last_metric
_last_metric = string
def init_params(params):
global _params
_params = copy.deepcopy(params)
def get_last_metric():
return json_tricks.loads(_last_metric)
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
from enum import Enum
class CommandType(Enum):
# in
Initialize = b'IN'
RequestTrialJobs = b'GE'
ReportMetricData = b'ME'
UpdateSearchSpace = b'SS'
AddCustomizedTrialJob = b'AD'
TrialEnd = b'EN'
Terminate = b'TE'
# out
NewTrialJob = b'TR'
NoMoreTrialJobs = b'NO'
KillTrialJob = b'KI'
try:
_in_file = open(3, 'rb')
_out_file = open(4, 'wb')
except OSError:
_msg = 'IPC pipeline not exists, maybe you are importing tuner/assessor from trial code?'
import logging
logging.getLogger(__name__).warning(_msg)
def send(command, data):
"""Send command to Training Service.
command: CommandType object.
data: string payload.
"""
data = data.encode('utf8')
assert len(data) < 1000000, 'Command too long'
msg = b'%b%06d%b' % (command.value, len(data), data)
_out_file.write(msg)
_out_file.flush()
def receive():
"""Receive a command from Training Service.
Returns a tuple of command (CommandType) and payload (str)
"""
header = _in_file.read(8)
length = int(header[2:])
data = _in_file.read(length)
command = CommandType(header[:2])
data = data.decode('utf8')
return command, data
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import inspect
import math
import random
from .common import env_args
from . import trial
__all__ = [
'choice',
'randint',
'uniform',
'quniform',
'loguniform',
'qloguniform',
'normal',
'qnormal',
'lognormal',
'qlognormal',
'function_choice'
]
# pylint: disable=unused-argument
if env_args.platform is None:
def choice(*options, name=None):
return random.choice(options)
def randint(upper, name=None):
return random.randrange(upper)
def uniform(low, high, name=None):
return random.uniform(low, high)
def quniform(low, high, q, name=None):
return round(random.uniform(low, high) / q) * q
def loguniform(low, high, name=None):
return math.exp(random.uniform(low, high))
def qloguniform(low, high, q, name=None):
return round(loguniform(low, high) / q) * q
def normal(mu, sigma, name=None):
return random.gauss(mu, sigma)
def qnormal(mu, sigma, q, name=None):
return round(random.gauss(mu, sigma) / q) * q
def lognormal(mu, sigma, name=None):
return math.exp(random.gauss(mu, sigma))
def qlognormal(mu, sigma, q, name=None):
return round(lognormal(mu, sigma) / q) * q
def function_choice(*funcs, name=None):
return random.choice(funcs)()
else:
def choice(*options, name=None):
return options[_get_param('choice', name)]
def randint(upper, name=None):
return _get_param('randint', name)
def uniform(low, high, name=None):
return _get_param('uniform', name)
def quniform(low, high, q, name=None):
return _get_param('quniform', name)
def loguniform(low, high, name=None):
return _get_param('loguniform', name)
def qloguniform(low, high, q, name=None):
return _get_param('qloguniform', name)
def normal(mu, sigma, name=None):
return _get_param('normal', name)
def qnormal(mu, sigma, q, name=None):
return _get_param('qnormal', name)
def lognormal(mu, sigma, name=None):
return _get_param('lognormal', name)
def qlognormal(mu, sigma, q, name=None):
return _get_param('qlognormal', name)
def function_choice(*funcs, name=None):
return funcs[_get_param('function_choice', name)]()
def _get_param(func, name):
# frames:
# layer 0: this function
# layer 1: the API function (caller of this function)
# layer 2: caller of the API function
frame = inspect.stack(0)[2]
filename = frame.filename
lineno = frame.lineno # NOTE: this is the lineno of caller's last argument
del frame # see official doc
module = inspect.getmodulename(filename)
if name is None:
name = '#{:d}'.format(lineno)
key = '{}/{}/{}'.format(module, name, func)
return trial.get_parameter(key)
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import json_tricks
from .common import env_args
from . import platform
__all__ = [
'get_parameters',
'report_intermediate_result',
'report_final_result',
]
_params = platform.get_parameters()
def get_parameters():
"""Returns a set of (hyper-)paremeters generated by Tuner."""
return _params['parameters']
def get_parameter(tag):
return get_parameters()[tag]
_intermediate_seq = 0
def report_intermediate_result(metric):
"""Reports intermediate result to Assessor.
metric: serializable object.
"""
global _intermediate_seq
metric = json_tricks.dumps({
'parameter_id': _params['parameter_id'],
'trial_job_id': env_args.trial_job_id,
'type': 'PERIODICAL',
'sequence': _intermediate_seq,
'value': metric
})
_intermediate_seq += 1
platform.send_metric(metric)
def report_final_result(metric):
"""Reports final result to tuner.
metric: serializable object.
"""
metric = json_tricks.dumps({
'parameter_id': _params['parameter_id'],
'trial_job_id': env_args.trial_job_id,
'type': 'FINAL',
'sequence': 0, # TODO: may be unnecessary
'value': metric
})
platform.send_metric(metric)
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import logging
import os
import json_tricks
from .common import init_logger
from .protocol import CommandType, send, receive
init_logger('tuner.log')
_logger = logging.getLogger(__name__)
class Tuner:
# pylint: disable=no-self-use,unused-argument
def generate_parameters(self, parameter_id):
"""Returns a set of trial (hyper-)parameters, as a serializable object.
User code must override either this function or 'generate_multiple_parameters()'.
parameter_id: int
"""
raise NotImplementedError('Tuner: generate_parameters not implemented')
def generate_multiple_parameters(self, parameter_id_list):
"""Returns multiple sets of trial (hyper-)parameters, as iterable of serializable objects.
Call 'generate_parameters()' by 'count' times by default.
User code must override either this function or 'generate_parameters()'.
parameter_id_list: list of int
"""
return [self.generate_parameters(parameter_id) for parameter_id in parameter_id_list]
def receive_trial_result(self, parameter_id, parameters, reward):
"""Invoked when a trial reports its final result. Must override.
parameter_id: int
parameters: object created by 'generate_parameters()'
reward: object reported by trial
"""
raise NotImplementedError('Tuner: receive_trial_result not implemented')
def receive_customized_trial_result(self, parameter_id, parameters, reward):
"""Invoked when a trial added by WebUI reports its final result. Do nothing by default.
parameter_id: int
parameters: object created by user
reward: object reported by trial
"""
_logger.info('Customized trial job %s ignored by tuner', parameter_id)
def update_search_space(self, search_space):
"""Update the search space of tuner. Must override.
search_space: JSON object
"""
raise NotImplementedError('Tuner: update_search_space not implemented')
def load_checkpoint(self, path):
"""Load the checkpoint of tuner.
path: checkpoint directory for tuner
"""
_logger.info('Load checkpoint ignored by tuner')
def save_checkpoint(self, path):
"""Save the checkpoint of tuner.
path: checkpoint directory for tuner
"""
_logger.info('Save checkpoint ignored by tuner')
def request_save_checkpoint(self):
"""Request to save the checkpoint of tuner
"""
self.save_checkpoint(os.getenv('NNI_CHECKPOINT_DIRECTORY'))
def run(self):
"""Run the tuner.
This function will never return unless raise.
"""
mode = os.getenv('NNI_MODE')
if mode == 'resume':
self.load_checkpoint(os.getenv('NNI_CHECKPOINT_DIRECTORY'))
while _handle_request(self):
pass
_logger.info('Terminated by NNI manager')
_next_parameter_id = 0
_trial_params = {}
'''key: trial job ID; value: parameters'''
_customized_parameter_ids = set()
def _create_parameter_id():
global _next_parameter_id # pylint: disable=global-statement
_next_parameter_id += 1
return _next_parameter_id - 1
def _pack_parameter(parameter_id, params, customized=False):
_trial_params[parameter_id] = params
ret = {
'parameter_id': parameter_id,
'parameter_source': 'customized' if customized else 'algorithm',
'parameters': params
}
return json_tricks.dumps(ret)
def _handle_request(tuner):
_logger.debug('waiting receive_message')
command, data = receive()
_logger.debug(command)
_logger.debug(data)
if command is CommandType.Terminate:
return False
data = json_tricks.loads(data)
if command is CommandType.RequestTrialJobs:
# data: number or trial jobs
ids = [_create_parameter_id() for _ in range(data)]
params_list = list(tuner.generate_multiple_parameters(ids))
assert len(ids) == len(params_list)
for i, _ in enumerate(ids):
send(CommandType.NewTrialJob, _pack_parameter(ids[i], params_list[i]))
elif command is CommandType.ReportMetricData:
# data: { 'type': 'FINAL', 'parameter_id': ..., 'value': ... }
if data['type'] == 'FINAL':
id_ = data['parameter_id']
if id_ in _customized_parameter_ids:
tuner.receive_customized_trial_result(id_, _trial_params[id_], data['value'])
else:
tuner.receive_trial_result(id_, _trial_params[id_], data['value'])
elif command is CommandType.UpdateSearchSpace:
# data: search space
tuner.update_search_space(data)
elif command is CommandType.AddCustomizedTrialJob:
# data: parameters
id_ = _create_parameter_id()
_customized_parameter_ids.add(id_)
send(CommandType.NewTrialJob, _pack_parameter(id_, data, customized=True))
else:
raise AssertionError('Unsupported command: %s' % command)
return True
# core
json_tricks
# hyperopt tuner
numpy
git+https://github.com/hyperopt/hyperopt.git#egg=hyperopt
# darkopt assessor
scipy
pymc3
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import os
import setuptools
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
setuptools.setup(
name = 'nni',
version = '0.0.1',
packages = setuptools.find_packages(exclude=['tests']),
python_requires = '>=3.5',
install_requires = [
'json_tricks',
'numpy',
'pymc3',
'scipy',
],
dependency_links = [
'git+https://github.com/hyperopt/hyperopt.git',
],
test_suite = 'tests',
author = 'Microsoft NNI Team',
author_email = 'nni@microsoft.com',
description = 'Python SDK for Neural Network Intelligence project',
license = 'MIT',
url = 'https://msrasrg.visualstudio.com/NeuralNetworkIntelligence',
long_description = read('README.md')
)
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import os
os.environ['NNI_PLATFORM'] = 'unittest'
os.environ['NNI_TRIAL_JOB_ID'] = 'test_trial_job_id'
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import nni.protocol
from nni.protocol import CommandType, send, receive
from nni.assessor import Assessor, AssessResult
from io import BytesIO
import json
from unittest import TestCase, main
_trials = [ ]
_end_trials = [ ]
class NaiveAssessor(Assessor):
def assess_trial(self, trial_job_id, trial_history):
_trials.append(trial_job_id)
if sum(trial_history) % 2 == 0:
return AssessResult.Good
else:
return AssessResult.Bad
def trial_end(self, trial_job_id, success):
_end_trials.append((trial_job_id, success))
_in_buf = BytesIO()
_out_buf = BytesIO()
def _reverse_io():
_in_buf.seek(0)
_out_buf.seek(0)
nni.protocol._out_file = _in_buf
nni.protocol._in_file = _out_buf
def _restore_io():
_in_buf.seek(0)
_out_buf.seek(0)
nni.protocol._in_file = _in_buf
nni.protocol._out_file = _out_buf
class AssessorTestCase(TestCase):
def test_assessor(self):
_reverse_io()
send(CommandType.ReportMetricData, '{"trial_job_id":"A","type":"PERIODICAL","sequence":0,"value":2}')
send(CommandType.ReportMetricData, '{"trial_job_id":"B","type":"PERIODICAL","sequence":0,"value":2}')
send(CommandType.ReportMetricData, '{"trial_job_id":"A","type":"PERIODICAL","sequence":1,"value":3}')
send(CommandType.TrialEnd, '{"trial_job_id":"A","event":"SYS_CANCELED"}')
send(CommandType.ReportMetricData, '{"trial_job_id":"B","type":"FINAL","sequence":0,"value":1}')
send(CommandType.TrialEnd, '{"trial_job_id":"B","event":"SUCCEEDED"}')
send(CommandType.NewTrialJob, 'null')
_restore_io()
assessor = NaiveAssessor()
try:
assessor.run()
except Exception as e:
self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.NewTrialJob')
self.assertEqual(_trials, ['A', 'B', 'A'])
self.assertEqual(_end_trials, [('A', False), ('B', True)])
_reverse_io()
command, data = receive()
self.assertIs(command, CommandType.KillTrialJob)
self.assertEqual(data, '"A"')
self.assertEqual(len(_out_buf.read()), 0)
if __name__ == '__main__':
main()
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import nni.protocol
from nni.protocol import CommandType, send, receive
from io import BytesIO
from unittest import TestCase, main
def _prepare_send():
nni.protocol._out_file = BytesIO()
return nni.protocol._out_file
def _prepare_receive(data):
nni.protocol._in_file = BytesIO(data)
class ProtocolTestCase(TestCase):
def test_send_en(self):
out_file = _prepare_send()
send(CommandType.NewTrialJob, 'CONTENT')
self.assertEqual(out_file.getvalue(), b'TR000007CONTENT')
def test_send_zh(self):
out_file = _prepare_send()
send(CommandType.NewTrialJob, '你好')
self.assertEqual(out_file.getvalue(), 'TR000006你好'.encode('utf8'))
def test_send_too_large(self):
_prepare_send()
exception = None
try:
send(CommandType.NewTrialJob, ' ' * 1_000_000)
except AssertionError as e:
exception = e
self.assertIsNotNone(exception)
def test_receive_en(self):
_prepare_receive(b'IN000005hello')
command, data = receive()
self.assertIs(command, CommandType.Initialize)
self.assertEqual(data, 'hello')
def test_receive_zh(self):
_prepare_receive('IN000006世界'.encode('utf8'))
command, data = receive()
self.assertIs(command, CommandType.Initialize)
self.assertEqual(data, '世界')
if __name__ == '__main__':
main()
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import nni
import nni.platform.test as test_platform
import nni.trial
from unittest import TestCase, main
lineno1 = 48
lineno2 = 58
class SmartParamTestCase(TestCase):
def setUp(self):
params = {
'test_smartparam/choice1/choice': 2,
'test_smartparam/#{:d}/uniform'.format(lineno1): '5',
'test_smartparam/func/function_choice': 1,
'test_smartparam/#{:d}/function_choice'.format(lineno2): 0
}
nni.trial._params = { 'parameter_id': 'test_trial', 'parameters': params }
def test_specified_name(self):
val = nni.choice('a', 'b', 'c', name = 'choice1')
self.assertEqual(val, 'c')
def test_default_name(self):
val = nni.uniform(1, 10) # NOTE: assign this line number to lineno1
self.assertEqual(val, '5')
def test_specified_name_func(self):
val = nni.function_choice(foo, bar, name = 'func')
self.assertEqual(val, 'bar')
def test_default_name_func(self):
val = nni.function_choice(
lambda: max(1, 2, 3),
lambda: 2 * 2 # NOTE: assign this line number to lineno2
)
self.assertEqual(val, 3)
def foo():
return 'foo'
def bar():
return 'bar'
if __name__ == '__main__':
main()
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import nni
import nni.platform.test as test_platform
import nni.trial
import numpy as np
from unittest import TestCase, main
class TrialTestCase(TestCase):
def setUp(self):
self._trial_params = { 'msg': 'hi', 'x': 123, 'dict': { 'key': 'value', 'y': None } }
nni.trial._params = { 'parameter_id': 'test_param', 'parameters': self._trial_params }
def test_get_parameters(self):
self.assertEqual(nni.get_parameters(), self._trial_params)
def test_report_intermediate_result(self):
nni.report_intermediate_result(123)
self.assertEqual(test_platform.get_last_metric(), {
'parameter_id': 'test_param',
'trial_job_id': 'test_trial_job_id',
'type': 'PERIODICAL',
'sequence': 0,
'value': 123
})
def test_report_final_result_simple(self):
self._test_report_final_result(123, 123)
def test_report_final_result_object(self):
obj = ['obj1', {'key1': 'v1', 'k2': None}, 233, 0.456]
self._test_report_final_result(obj, obj)
def test_report_final_result_numpy(self):
self._test_report_final_result(np.float32(0.25), 0.25)
def test_report_final_result_nparray(self):
arr = np.array([[1, 2, 3], [4, 5, 6]])
nni.report_final_result(arr)
out = test_platform.get_last_metric()
self.assertEqual(len(arr), 2)
self.assertEqual(len(arr[0]), 3)
self.assertEqual(len(arr[1]), 3)
self.assertEqual(arr[0][0], 1)
self.assertEqual(arr[0][1], 2)
self.assertEqual(arr[0][2], 3)
self.assertEqual(arr[1][0], 4)
self.assertEqual(arr[1][1], 5)
self.assertEqual(arr[1][2], 6)
def _test_report_final_result(self, in_, out):
nni.report_final_result(in_)
self.assertEqual(test_platform.get_last_metric(), {
'parameter_id': 'test_param',
'trial_job_id': 'test_trial_job_id',
'type': 'FINAL',
'sequence': 0,
'value': out
})
if __name__ == '__main__':
main()
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ==================================================================================================
import nni.protocol
from nni.protocol import CommandType, send, receive
from nni.tuner import Tuner
from io import BytesIO
import json
from unittest import TestCase, main
class NaiveTuner(Tuner):
def __init__(self):
self.param = 0
self.trial_results = [ ]
self.search_space = None
def generate_parameters(self, parameter_id):
# report Tuner's internal states to generated parameters,
# so we don't need to pause the main loop
self.param += 2
return {
'param': self.param,
'trial_results': self.trial_results,
'search_space': self.search_space
}
def receive_trial_result(self, parameter_id, parameters, reward):
self.trial_results.append((parameter_id, parameters['param'], reward, False))
def receive_customized_trial_result(self, parameter_id, parameters, reward):
self.trial_results.append((parameter_id, parameters['param'], reward, True))
def update_search_space(self, search_space):
self.search_space = search_space
_in_buf = BytesIO()
_out_buf = BytesIO()
def _reverse_io():
_in_buf.seek(0)
_out_buf.seek(0)
nni.protocol._out_file = _in_buf
nni.protocol._in_file = _out_buf
def _restore_io():
_in_buf.seek(0)
_out_buf.seek(0)
nni.protocol._in_file = _in_buf
nni.protocol._out_file = _out_buf
class TunerTestCase(TestCase):
def test_tuner(self):
_reverse_io() # now we are sending to Tuner's incoming stream
send(CommandType.RequestTrialJobs, '2')
send(CommandType.ReportMetricData, '{"parameter_id":0,"type":"PERIODICAL","value":10}')
send(CommandType.ReportMetricData, '{"parameter_id":1,"type":"FINAL","value":11}')
send(CommandType.UpdateSearchSpace, '{"name":"SS0"}')
send(CommandType.AddCustomizedTrialJob, '{"param":-1}')
send(CommandType.ReportMetricData, '{"parameter_id":2,"type":"FINAL","value":22}')
send(CommandType.RequestTrialJobs, '1')
send(CommandType.KillTrialJob, 'null')
_restore_io()
tuner = NaiveTuner()
try:
tuner.run()
except Exception as e:
self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.KillTrialJob')
_reverse_io() # now we are receiving from Tuner's outgoing stream
self._assert_params(0, 2, [ ], None)
self._assert_params(1, 4, [ ], None)
command, data = receive() # this one is customized
data = json.loads(data)
self.assertIs(command, CommandType.NewTrialJob)
self.assertEqual(data, {
'parameter_id': 2,
'parameter_source': 'customized',
'parameters': { 'param': -1 }
})
self._assert_params(3, 6, [[1,4,11,False], [2,-1,22,True]], {'name':'SS0'})
self.assertEqual(len(_out_buf.read()), 0) # no more commands
def _assert_params(self, parameter_id, param, trial_results, search_space):
command, data = receive()
self.assertIs(command, CommandType.NewTrialJob)
data = json.loads(data)
self.assertEqual(data['parameter_id'], parameter_id)
self.assertEqual(data['parameter_source'], 'algorithm')
self.assertEqual(data['parameters']['param'], param)
self.assertEqual(data['parameters']['trial_results'], trial_results)
self.assertEqual(data['parameters']['search_space'], search_space)
if __name__ == '__main__':
main()
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# webui
NNI is a research platform for metalearning. It provides easy-to-use interface so that you could perform neural architecture search, hyperparameter optimization and optimizer design for your own problems and models.
Web UI allows user to monitor the status of the NNI system using a graphical interface.
## Deployment
### To start the webui
> $ yarn
> $ yarn start
## Usage
### View summary page
Click the tab "Overview".
* See good performance trial.
* See search_space json.
* See complete trial cdf graph.
### View job accuracy
Click the tab "Optimization Progress" to see the point graph of all trials. Hover every point to see its specific accuracy.
### View hyper parameter
Click the tab "Hyper Parameter" to see the parallel graph.
* You can select the percentage to cut down some lines.
* Choose two axes to swap its positions
### View trial status
Click the tab "Trial Status" to see the status of the all trials. Specifically:
* Running trial: running trial's duration in the bar graph.
* Trial detail: trial's id, trial's duration, start time, end time, status and accuracy.
* Kill: you can kill a job that status is running.
* Tensor: you can see a job in the tensorflow graph, it will link to the Tensorboard page.
* Log: click the button, you can see the log about NNI and pai.
### Control
Click the tab "Control" to add a new trial or update the search_space file.
### View Tensorboard Graph
Click the tab "Tensorboard" to see a job in the tensorflow graph.
\ No newline at end of file
const tsImportPluginFactory = require('ts-import-plugin')
const { getLoader } = require("react-app-rewired");
module.exports = function override(config, env) {
const tsLoader = getLoader(
config.module.rules,
rule =>
rule.loader &&
typeof rule.loader === 'string' &&
rule.loader.includes('ts-loader')
);
tsLoader.options = {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}) ]
})
};
return config;
}
\ No newline at end of file
{
"name": "my-app",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"base16": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
},
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "0.4.21"
}
},
"fbemitter": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-2.1.1.tgz",
"integrity": "sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=",
"requires": {
"fbjs": "0.8.16"
}
},
"fbjs": {
"version": "0.8.16",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
"integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
"requires": {
"core-js": "1.2.7",
"isomorphic-fetch": "2.2.1",
"loose-envify": "1.3.1",
"object-assign": "4.1.1",
"promise": "7.3.1",
"setimmediate": "1.0.5",
"ua-parser-js": "0.7.17"
}
},
"flux": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/flux/-/flux-3.1.3.tgz",
"integrity": "sha1-0jvtUVp5oi2TOrU6tK2hnQWy8Io=",
"requires": {
"fbemitter": "2.1.1",
"fbjs": "0.8.16"
}
},
"iconv-lite": {
"version": "0.4.21",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"requires": {
"safer-buffer": "2.1.2"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "1.7.3",
"whatwg-fetch": "2.0.4"
}
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"lodash.curry": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
"integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA="
},
"lodash.flow": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
"integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o="
},
"loose-envify": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
"requires": {
"js-tokens": "3.0.2"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "0.1.12",
"is-stream": "1.1.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "2.0.6"
}
},
"prop-types": {
"version": "15.6.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz",
"integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==",
"requires": {
"fbjs": "0.8.16",
"loose-envify": "1.3.1",
"object-assign": "4.1.1"
}
},
"pure-color": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
"integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4="
},
"react-base16-styling": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
"integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=",
"requires": {
"base16": "1.0.0",
"lodash.curry": "4.1.1",
"lodash.flow": "3.5.0",
"pure-color": "1.3.0"
}
},
"react-json-view": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.16.1.tgz",
"integrity": "sha512-9gx2S+b9+LHbjnIzIXrcDU14YI5KP3hhDgNHrQiLsV3dtnzoT8m6j37h7dpCaO1hPLZEc3Q/6VS1QjiLi0HT/w==",
"requires": {
"flux": "3.1.3",
"react-base16-styling": "0.5.3",
"react-textarea-autosize": "5.2.1"
}
},
"react-textarea-autosize": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz",
"integrity": "sha512-bx6z2I35aapr71ggw2yZIA4qhmqeTa4ZVsSaTeFvtf9kfcZppDBh2PbMt8lvbdmzEk7qbSFhAxR9vxEVm6oiMg==",
"requires": {
"prop-types": "15.6.1"
}
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"ua-parser-js": {
"version": "0.7.17",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
"integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
},
"whatwg-fetch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
}
}
}
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"antd": "^3.8.1",
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"echarts": "^4.1.0",
"echarts-for-react": "^2.0.14",
"react": "^16.4.2",
"react-app-rewired": "^1.5.2",
"react-dom": "^16.4.2",
"react-json-tree": "^0.11.0",
"react-router": "3.2.1"
},
"scripts": {
"start": "react-app-rewired start --scripts-version react-scripts-ts",
"build": "react-app-rewired build --scripts-version react-scripts-ts",
"test": "react-app-rewired test --env=jsdom --scripts-version react-scripts-ts",
"eject": "react-scripts-ts eject"
},
"devDependencies": {
"@types/node": "^10.7.0",
"@types/react-router": "3.0.15",
"@types/react-json-tree": "^0.6.8",
"@types/react-dom": "^16.0.7",
"react-scripts-ts": "^2.17.0",
"ts-import-plugin": "^1.5.4",
"typescript": "^3.0.1"
}
}
\ 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