From 1cc1d6b5569ea321116e38debda1a785d3e78002 Mon Sep 17 00:00:00 2001 From: Jin Haifeng Date: Sat, 17 Mar 2018 09:34:23 -0500 Subject: [PATCH] Distance (#4) * deleted redundant graph test * edit_distance implemented --- autokeras/bayesian.py | 53 ++++++++++++++++++++++++++++++------------ tests/test_bayesian.py | 2 +- tests/test_graph.py | 37 ----------------------------- 3 files changed, 39 insertions(+), 53 deletions(-) diff --git a/autokeras/bayesian.py b/autokeras/bayesian.py index a085866d8..12b7bd055 100644 --- a/autokeras/bayesian.py +++ b/autokeras/bayesian.py @@ -1,26 +1,49 @@ +import math import numpy as np from scipy.linalg import cholesky, cho_solve +from scipy.optimize import linear_sum_assignment -def edit_distance(x, y): - ret = 0 - ret += abs(x.n_conv - y.n_conv) - ret += abs(x.n_dense - y.n_dense) +def layer_distance(a, b): + return abs(a - b) * 1.0 / max(a, b) + + +def layers_distance(list_a, list_b): + len_a = len(list_a) + len_b = len(list_b) + f = np.zeros((len_a + 1, len_b + 1)) + f[-1][-1] = 0 + for i in range(-1, len_a): + f[i][-1] = i + 1 + for j in range(-1, len_b): + f[-1][j] = j + 1 + for i in range(len_a): + for j in range(len_b): + f[i][j] = min(f[i][j - 1] + 1, f[i - 1][j] + 1, f[i - 1][j - 1] + layer_distance(list_a[i], list_b[j])) + return f[len_a][len_b] - for i in range(min(x.n_conv, y.n_conv)): - a = x.conv_widths[i] - b = y.conv_widths[i] - ret += abs(a - b) / max(a, b) - for i in range(min(x.n_dense, y.n_dense)): - a = x.dense_widths[i] - b = y.dense_widths[i] - ret += abs(a - b) / max(a, b) +def skip_connection_distance(a, b): + if a[2] != b[2]: + return 1.0 + len_a = abs(a[1] - a[0]) + len_b = abs(b[1] - b[0]) + return abs(a[0] - b[0]) + abs(len_a - len_b) - for connection in x.skip_connections: - if connection not in y.skip_connections: - ret += 1 +def skip_connections_distance(list_a, list_b): + distance_matrix = np.zeros((len(list_a), len(list_b))) + for i, a in enumerate(list_a): + for j, b in enumerate(list_b): + distance_matrix[i][j] = skip_connection_distance(a, b) + return distance_matrix[linear_sum_assignment(distance_matrix)].sum() + abs(len(list_a) - len(list_b)) + + +def edit_distance(x, y): + ret = 0 + ret += layers_distance(x.conv_widths, y.conv_widths) + ret += layers_distance(x.dense_widths, y.dense_widths) + ret += skip_connections_distance(x.skip_connections, y.skip_connections) return ret diff --git a/tests/test_bayesian.py b/tests/test_bayesian.py index 2cbbe553e..7dfac694c 100644 --- a/tests/test_bayesian.py +++ b/tests/test_bayesian.py @@ -6,7 +6,7 @@ def test_edit_distance(): descriptor1 = Graph(get_add_skip_model()).extract_descriptor() descriptor2 = Graph(get_concat_skip_model()).extract_descriptor() - assert edit_distance(descriptor1, descriptor2) == 3 + assert edit_distance(descriptor1, descriptor2) == 2.0 def test_gpr(): diff --git a/tests/test_graph.py b/tests/test_graph.py index e8de1ae30..7856037cd 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -98,19 +98,6 @@ def test_dense_wider(): assert np.sum(np.abs(output1 - output2)) < 1e-4 -def test_skip_add(): - model = get_conv_model() - graph = NetworkMorphismGraph(model) - graph.to_add_skip_model(graph.layer_to_id[model.layers[1]], graph.layer_to_id[model.layers[4]]) - new_model = graph.produce_model() - input_data = get_conv_data() - - output1 = model.predict_on_batch(input_data).flatten() - output2 = new_model.predict_on_batch(input_data).flatten() - - assert np.array_equal(output1, output2) - - def test_skip_add_over_pooling_stub(): model = to_stub_model(get_pooling_model()) graph = Graph(model) @@ -133,19 +120,6 @@ def test_skip_add_over_pooling(): assert np.array_equal(output1, output2) -def test_skip_concatenate(): - model = get_add_skip_model() - graph = NetworkMorphismGraph(model) - graph.to_concat_skip_model(graph.layer_to_id[model.layers[4]], graph.layer_to_id[model.layers[4]]) - new_model = graph.produce_model() - input_data = get_conv_data() - - output1 = model.predict_on_batch(input_data).flatten() - output2 = new_model.predict_on_batch(input_data).flatten() - - assert np.sum(np.abs(output1 - output2)) < 3e-1 - - def test_skip_concat_over_pooling_stub(): model = to_stub_model(get_pooling_model()) graph = Graph(model) @@ -170,17 +144,6 @@ def test_skip_concat_over_pooling(): assert np.sum(np.abs(output1 - output2)) < 4e-1 -def test_copy_model(): - model = get_add_skip_model() - new_model = NetworkMorphismGraph(model).produce_model() - input_data = get_conv_data() - - output1 = model.predict_on_batch(input_data).flatten() - output2 = new_model.predict_on_batch(input_data).flatten() - - assert np.sum(output1 - output2) == 0 - - def test_extract_descriptor_add(): model = get_add_skip_model() descriptor = Graph(model).extract_descriptor()