def mutate_arch(parent_arch): # Choose one of the three mutations mutation = np.random.choice( ['identity', 'hidden_state_mutation', 'op_mutation']) adjacency_matrix, node_list = copy.deepcopy( parent_arch.adjacency_matrix), copy.deepcopy(parent_arch.node_list) if mutation == 'identity': return Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list) elif mutation == 'hidden_state_mutation': # Pick one of the intermediate nodes in the graph (neither input nor output) if type(search_space) == SearchSpace1: # Node 1 has now choice for node 2 as it always has 2 parents low = 3 else: low = 2 random_node = np.random.randint(low=low, high=adjacency_matrix.shape[-1]) # Pick one of the parents of the node # parent_of_node_to_modify = np.random.choice(adjacency_matrix[:random_node, random_node].nonzero()[0]) parents = adjacency_matrix[:random_node, random_node].nonzero()[0] #print('matrix', adjacency_matrix) #print('parents', parents) if parents.any(): parent_of_node_to_modify = np.random.choice(parents) # Select a new parent for this node, (needs to be different from previous parent) new_parent_of_node = np.random.choice( np.argwhere(adjacency_matrix[:random_node, random_node] == 0).flatten()) # Remove old parent from child adjacency_matrix[parent_of_node_to_modify, random_node] = 0 # Add new parent to child adjacency_matrix[new_parent_of_node, random_node] = 1 # Create new child config return Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list) else: # don't make any changes return Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list) else: # op_mutation OPS = [CONV3X3, CONV1X1, MAXPOOL3X3] op_idx_to_change = np.random.randint(len(node_list)) # Remove current op on selected idx (because we want a new op) OPS.remove(node_list[op_idx_to_change]) # Select one of the remaining ops new_op = np.random.choice(OPS) node_list[op_idx_to_change] = new_op return Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list)
def get_neighborhood(arch): neighbors = [] for i in range(len(arch.node_list)): adjacency_matrix, node_list = copy.deepcopy( arch.adjacency_matrix), copy.deepcopy(arch.node_list) OPS = [CONV3X3, CONV1X1, MAXPOOL3X3] OPS.remove(node_list[i]) new_op = np.random.choice(OPS) node_list[i] = new_op neighbors.append( Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list)) if type(search_space) == SearchSpace1: # Node 1 has now choice for node 2 as it always has 2 parents low = 3 else: low = 2 for i in range(low, arch.adjacency_matrix.shape[-1]): parents = arch.adjacency_matrix[:i, i].nonzero()[0] for parent in parents: for new_parent in np.argwhere( arch.adjacency_matrix[:i, i] == 0).flatten(): # Select a new parent for this node, (needs to be different from previous parent) adjacency_matrix = copy.deepcopy(arch.adjacency_matrix) node_list = copy.deepcopy(arch.node_list) adjacency_matrix[parent, i] = 0 # Add new parent to child adjacency_matrix[new_parent, i] = 1 # Create new child config neighbors.append( Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list)) return neighbors
def objective_function(self, nasbench, config, budget=108): adjacency_matrix, node_list = super( SearchSpace2, self).convert_config_to_nasbench_format(config) # adjacency_matrix = upscale_to_nasbench_format(adjacency_matrix) node_list = [INPUT, *node_list, CONV1X1, OUTPUT] adjacency_list = adjacency_matrix.astype(np.int).tolist() model_spec = api.ModelSpec(matrix=adjacency_list, ops=node_list) nasbench_data = nasbench.query(model_spec, epochs=budget) # record the data to history architecture = Model() arch = Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list) architecture.update_data(arch, nasbench_data, budget) self.run_history.append(architecture) return nasbench_data['validation_accuracy'], nasbench_data[ 'training_time']
def random_architecture(): adjacency_matrix, node_list = search_space.sample_with_loose_ends() architecture = Architecture(adjacency_matrix=adjacency_matrix, node_list=node_list) return architecture