def test_modify_hyperparameters(self, lp_mock, io_mock): """If a primitive method modifies the hyperparameters, changes should not persist.""" def primitive(a_list_param): a_list_param.append('b') io_mock.return_value = primitive lp_mock.return_value = { 'name': 'a_primitive', 'primitive': 'a_primitive', 'produce': { 'args': [], 'output': [] } } mlblock = MLBlock('a_primitive') hyperparameters = { 'a_list_param': ['a'] } mlblock._hyperparameters = hyperparameters mlblock.produce() assert 'b' not in hyperparameters['a_list_param']
def test_get_hyperparameters(self): """get_hyperparameters has to return a deepcopy of the _hyperparameters attribute.""" mlblock = MLBlock('given_primitive_name') hyperparameters = {'a_list_param': ['a']} mlblock._hyperparameters = hyperparameters returned = mlblock.get_hyperparameters() assert returned == hyperparameters assert returned is not hyperparameters returned['a_list_param'].append('b') assert 'b' not in hyperparameters['a_list_param']
def test__get_tunable_no_conditionals(self): """If there are no conditionals, tunables are returned unmodified.""" # setup init_params = { 'an_init_param': 'a_value' } hyperparameters = { 'tunable': { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] } } } # run tunable = MLBlock._get_tunable(hyperparameters, init_params) # assert expected = { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] } } assert tunable == expected
def _build_blocks(self): blocks = OrderedDict() block_names_count = Counter() for primitive in self.primitives: if isinstance(primitive, str): primitive_name = primitive else: primitive_name = primitive['name'] try: block_names_count.update([primitive_name]) block_count = block_names_count[primitive_name] block_name = '{}#{}'.format(primitive_name, block_count) block_params = self.init_params.get(block_name, dict()) if not block_params: block_params = self.init_params.get(primitive_name, dict()) if block_params and block_count > 1: LOGGER.warning(("Non-numbered init_params are being used " "for more than one block %s."), primitive_name) block = MLBlock(primitive, **block_params) blocks[block_name] = block except Exception: LOGGER.exception("Exception caught building MLBlock %s", primitive) raise return blocks
def __init__(self, primitives, init_params=None, input_names=None, output_names=None): self.primitives = primitives self.init_params = init_params or dict() self.blocks = OrderedDict() block_names_count = Counter() for primitive in primitives: try: block_names_count.update([primitive]) block_count = block_names_count[primitive] block_name = '{}#{}'.format(primitive, block_count) block_params = self.init_params.get(block_name, dict()) if not block_params: block_params = self.init_params.get(primitive, dict()) if block_params and block_count > 1: LOGGER.warning( ("Non-numbered init_params are being used " "for more than one block %s."), primitive) block = MLBlock(primitive, **block_params) self.blocks[block_name] = block except Exception: LOGGER.exception("Exception caught building MLBlock %s", primitive) raise self.input_names = input_names or dict() self.output_names = output_names or dict() self._tunable_hyperparameters = self._get_tunable_hyperparameters()
def test___init__(self, load_primitive_mock, import_object_mock, set_hps_mock): load_primitive_mock.return_value = { 'primitive': 'a_primitive_name', 'produce': { 'args': [{ 'name': 'argument' }], 'output': [] } } mlblock = MLBlock('given_primitive_name', argument='value') assert mlblock.name == 'given_primitive_name' assert mlblock.primitive == import_object_mock.return_value assert mlblock._fit == dict() assert mlblock.fit_args == list() assert mlblock.fit_method is None produce = {'args': [{'name': 'argument'}], 'output': []} assert mlblock._produce == produce assert mlblock.produce_args == produce['args'] assert mlblock.produce_output == produce['output'] assert mlblock.produce_method is None assert mlblock._class is False assert mlblock._hyperparameters == dict() assert mlblock._fit_params == dict() assert mlblock._produce_params == {'argument': 'value'} assert mlblock._tunable == dict() set_hps_mock.assert_called_once_with(dict())
def test_get_hyperparameters(self, load_primitive_mock, import_object_mock): """get_hyperparameters has to return a copy of the _hyperparameters attribute.""" load_primitive_mock.return_value = { 'primitive': 'a_primitive_name', 'produce': { 'args': [], 'output': [] } } mlblock = MLBlock('given_primitive_name') hyperparameters = dict() mlblock._hyperparameters = hyperparameters returned = mlblock.get_hyperparameters() assert returned == hyperparameters assert returned is not hyperparameters
def test__get_tunable_no_condition(self): """If there is a conditional but no condition, the default is used.""" # setup init_params = { 'an_init_param': 'a_value' } hyperparameters = { 'tunable': { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'conditional', 'condition': 'a_condition', 'default': { 'type': 'float', 'default': 0.1, 'values': [0, 1] }, 'values': { 'not_a_match': { 'type': 'str', 'default': 'a', 'values': ['a', 'b'] }, 'neither_a_match': { 'type': 'int', 'default': 0, 'range': [1, 10] } } } } } # run tunable = MLBlock._get_tunable(hyperparameters, init_params) # assert expected = { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'float', 'default': 0.1, 'values': [0, 1] } } assert tunable == expected
def test__get_tunable_condition_match(self): """If there is a conditional and it matches, only that part is returned.""" # setup init_params = { 'a_condition': 'a_match' } hyperparameters = { 'tunable': { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'conditional', 'condition': 'a_condition', 'default': { 'type': 'float', 'default': 0.1, 'values': [0, 1] }, 'values': { 'not_a_match': { 'type': 'str', 'default': 'a', 'values': ['a', 'b'] }, 'a_match': { 'type': 'int', 'default': 0, 'range': [1, 10] } } } } } # run tunable = MLBlock._get_tunable(hyperparameters, init_params) # assert expected = { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'int', 'default': 0, 'range': [1, 10] } } assert tunable == expected
def test___str__(self, load_primitive_mock, import_object_mock): load_primitive_mock.return_value = { 'primitive': 'a_primitive_name', 'produce': { 'args': [], 'output': [] } } mlblock = MLBlock('given_primitive_name') assert str(mlblock) == 'MLBlock - given_primitive_name'
def test__get_tunable_condition_match_null(self): """If there is a match and it is null (None), this param is not included. This stands even if the default is not null. """ # setup init_params = { 'a_condition': 'a_match' } hyperparameters = { 'tunable': { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'conditional', 'condition': 'a_condition', 'default': { 'type': 'float', 'default': 0.1, 'values': [0, 1] }, 'values': { 'not_a_match': { 'type': 'str', 'default': 'a', 'values': ['a', 'b'] }, 'a_match': None } } } } # run tunable = MLBlock._get_tunable(hyperparameters, init_params) # assert expected = { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] } } assert tunable == expected
def build_mlblock(self): block_name = self.block_json['name'] fixed_hyperparams = self.block_json['fixed_hyperparameters'] tunable_hyperparams = self.get_mlhyperparams(block_name) model = self.build_mlblock_model(fixed_hyperparams, tunable_hyperparams) instance = MLBlock(name=block_name, model=model, fixed_hyperparams=fixed_hyperparams, tunable_hyperparams=tunable_hyperparams) self.replace_instance_methods(instance) return instance
def test__get_tunable_condition_default_null(self): """If there is no match and default is null (None), this param is not included.""" # setup init_params = { 'a_condition': 'not_a_match' } hyperparameters = { 'tunable': { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] }, 'this_is_conditional': { 'type': 'conditional', 'condition': 'a_condition', 'default': None, 'values': { 'also_not_a_match': { 'type': 'str', 'default': 'a', 'values': ['a', 'b'] }, 'neither_a_match': { 'type': 'int', 'default': 0, 'range': [1, 10] } } } } } # run tunable = MLBlock._get_tunable(hyperparameters, init_params) # assert expected = { 'this_is_not_conditional': { 'type': 'int', 'default': 1, 'range': [1, 10] } } assert tunable == expected