def test_scores_zero(content, style): """Scores must be zero if inputs vary on different dimensions. """ content[:, 0], style[:, 1] = 0.0, 0.0 matcher = FeatureMatcher(content, style) matcher.compare_features_matrix(split=2) assert pytest.approx(0.0) == matcher.repro_target.scores.max() assert pytest.approx(0.0) == matcher.repro_sources.scores.max()
def test_scores_one(content, style): """Scores must be one if inputs only vary on one dimension. """ content[:, 0], style[:, 0] = 0.0, 0.0 matcher = FeatureMatcher(content, style) matcher.compare_features_matrix(split=2) assert pytest.approx(1.0) == matcher.repro_target.scores.min() assert pytest.approx(1.0) == matcher.repro_sources.scores.min()
def test_scores_range_matrix(target, source): """Determine that the scores of random patches are in correct range. """ matcher = FeatureMatcher(target, source) matcher.compare_features_matrix(split=2) assert matcher.repro_target.scores.min() >= 0.0 assert matcher.repro_target.scores.max() <= 1.0 assert matcher.repro_sources.scores.min() >= 0.0 assert matcher.repro_sources.scores.max() <= 1.0
def test_scores_identity(array): """The score of the identity operation with linear indices should be one. """ matcher = FeatureMatcher(array, array) matcher.repro_target.from_linear(array.shape) matcher.repro_sources.from_linear(array.shape) matcher.compare_features_matrix(split=2) assert pytest.approx(1.0) == matcher.repro_target.scores.min() assert pytest.approx(1.0) == matcher.repro_sources.scores.min()
def test_compare_random_converges(target, source): """Determine that the scores of random patches are in correct range. """ matcher1 = FeatureMatcher(target, source) matcher1.compare_features_matrix(split=2) matcher2 = FeatureMatcher(target, source) for _ in range(500): matcher2.compare_features_random(split=2) missing = ( (matcher1.repro_target.indices != matcher2.repro_target.indices).sum() + (matcher1.repro_sources.indices != matcher2.repro_sources.indices).sum() ) if missing == 0: break assert (matcher1.repro_target.indices != matcher2.repro_target.indices).sum() <= 2 assert pytest.approx(0.0, abs=1e-6) == torch.dist( matcher1.repro_target.scores, matcher2.repro_target.scores ) assert matcher2.repro_sources.indices.min() != -1 assert (matcher1.repro_sources.indices != matcher2.repro_sources.indices).sum() <= 2 assert pytest.approx(0.0, abs=1e-6) == torch.dist( matcher1.repro_sources.scores, matcher2.repro_sources.scores )
def test_nearest_neighbor_vs_matcher(content, style): """The score of the identity operation with linear indices should be one. """ matcher = FeatureMatcher(content, style) matcher.compare_features_matrix(split=1) ida, idb = nearest_neighbors_1d(content.flatten(2), style.flatten(2), split=1) ima = (matcher.repro_target.indices[:, 0] * style.shape[2] + matcher.repro_target.indices[:, 1]) assert (ima.flatten(1) != ida).sum() == 0 imb = (matcher.repro_sources.indices[:, 0] * content.shape[2] + matcher.repro_sources.indices[:, 1]) assert (imb.flatten(1) != idb).sum() == 0
def test_indices_symmetry_matrix(content, style): """The indices of the symmerical operation must be equal. """ matcher1 = FeatureMatcher(content, style) matcher2 = FeatureMatcher(style, content) matcher1.compare_features_matrix(split=2) matcher2.compare_features_matrix(split=2) assert (matcher1.repro_target.indices != matcher2.repro_sources.indices).sum() <= 2 assert (matcher1.repro_sources.indices != matcher2.repro_target.indices).sum() <= 2
def test_compare_inverse_symmetrical(array): """Check that doing the identity comparison also projects the inverse coordinates into the other buffer. """ matcher = FeatureMatcher(array, array) matcher.repro_target.from_linear(array.shape) matcher.repro_sources.indices.zero_() matcher.compare_features_identity() matcher.compare_features_inverse(split=1) assert (matcher.repro_target.indices != matcher.repro_sources.indices).sum() == 0 matcher.repro_target.indices.zero_() matcher.repro_target.scores.fill_(float("-inf")) matcher.compare_features_identity() matcher.compare_features_inverse(split=1) assert (matcher.repro_target.indices != matcher.repro_sources.indices).sum() == 0
def test_indices_same_rotate(content, style): """The score of the identity operation with linear indices should be one. """ matcher1 = FeatureMatcher(content, style) matcher1.compare_features_matrix(split=2) matcher2 = FeatureMatcher(content, style.permute(0, 1, 3, 2)) matcher2.compare_features_matrix(split=2) assert (matcher1.repro_target.indices[:, 0] != matcher2.repro_target.indices[:, 1]).sum() <= 1 assert (matcher2.repro_target.indices[:, 1] != matcher1.repro_target.indices[:, 0]).sum() <= 1
def test_scatter_2d_single_float(array): matcher = FeatureMatcher(array, array) matcher.repro_target.scores.zero_() indices = torch.ones(size=(1, 2, 1, 1), dtype=torch.int64) values = torch.full((1, 1, 1, 1), 2.34, dtype=torch.float32) torch_scatter_2d(matcher.repro_target.scores, indices, values) assert matcher.repro_target.scores[:, :, 1, 1] == 2.34 assert matcher.repro_target.scores[:, :, 0, 0] == 0.0
def test_indices_same_split(content, style): """The score of the identity operation with linear indices should be one. """ matcher = FeatureMatcher(content, style) matcher.compare_features_matrix(split=1) target_indices = matcher.repro_target.indices.clone() source_indices = matcher.repro_sources.indices.clone() for split in [2, 4, 8]: matcher.update_target(content) matcher.compare_features_matrix(split=split) assert (target_indices != matcher.repro_target.indices).sum() <= 2 assert (source_indices != matcher.repro_sources.indices).sum() <= 2
def test_propagate_up_left(array): """Propagating the identity transformation expects indices to propagate one cell at a time, here up and towards the left. """ y, x = array.shape[-2:] matcher = FeatureMatcher(array, array) indices, scores = matcher.repro_target.indices, matcher.repro_target.scores indices.zero_() indices[:, 0, -1, -1] = y - 1 indices[:, 1, -1, -1] = x - 1 scores[:, 0, -1, -1] = 1.0 matcher.compare_features_nearby(radius=1, split=2) assert ( indices[:, :, y - 2, x - 1] == torch.tensor([y - 2, x - 1], dtype=torch.long) ).all() assert ( indices[:, :, y - 1, x - 2] == torch.tensor([y - 1, x - 2], dtype=torch.long) ).all() matcher.compare_features_nearby(radius=1, split=2) assert ( indices[:, :, y - 2, x - 2] == torch.tensor([y - 2, x - 2], dtype=torch.long) ).all()
def test_scatter_2d_single_long(array): matcher = FeatureMatcher(array, array) matcher.repro_target.indices.zero_() indices = torch.ones(size=(1, 2, 1, 1), dtype=torch.int64) values = torch.tensor([[234, 345]], dtype=torch.int64).view(1, 2, 1, 1) torch_scatter_2d(matcher.repro_target.indices, indices, values) assert (matcher.repro_target.indices == 234).sum() == 1 assert (matcher.repro_target.indices == 345).sum() == 1 assert matcher.repro_target.indices[:, 0, 1, 1] == 234 assert matcher.repro_target.indices[:, 1, 1, 1] == 345 assert matcher.repro_target.indices[:, :, 0, 0].max() == 0
def test_compare_inverse_asymmetrical(content, style): """Check that doing the identity comparison also projects the inverse coordinates into the other buffer. """ # Set corner pixel as identical, so it matches 100%. content[:, :, -1, -1] = style[:, :, -1, -1] matcher = FeatureMatcher(content, style) matcher.repro_target.from_linear(style.shape) matcher.repro_sources.indices.zero_() matcher.compare_features_identity() matcher.compare_features_inverse(split=2) assert matcher.repro_sources.indices.max() > 0 matcher.repro_sources.from_linear(content.shape) matcher.repro_target.indices.zero_() matcher.repro_target.scores.zero_() matcher.compare_features_identity() matcher.compare_features_inverse(split=2) assert matcher.repro_target.indices.max() > 0
def test_scores_improve(content, style): """Scores must be one if inputs only vary on one dimension. """ matcher = FeatureMatcher(content, style) matcher.compare_features_identity() before = matcher.repro_target.scores.sum() matcher.compare_features_random(times=1) after = matcher.repro_target.scores.sum() event("equal? %i" % int(after == before)) assert after >= before
def test_scores_target_bias_matrix(array): matcher = FeatureMatcher(torch.cat([array, array], dim=2), array) matcher.repro_sources.biases[:, :, 11:] = 1.0 matcher.repro_sources.scores.zero_() matcher.compare_features_matrix(split=2) assert (matcher.repro_sources.indices[:, 0] >= 11).all() matcher.repro_sources.biases[:, :, 11:] = 0.0 matcher.repro_sources.biases[:, :, :11] = 1.0 matcher.repro_sources.scores.zero_() matcher.compare_features_matrix(split=2) assert (matcher.repro_sources.indices[:, 0] < 11).all()
def test_scores_source_bias_matrix(array): matcher = FeatureMatcher(array, torch.cat([array, array], dim=2)) matcher.repro_target.biases[:, :, 9:] = 1.0 matcher.repro_target.scores.zero_() matcher.compare_features_matrix(split=2) assert (matcher.repro_target.indices[:, 0] >= 9).all() matcher.repro_target.biases[:, :, 9:] = 0.0 matcher.repro_target.biases[:, :, :9] = 1.0 matcher.repro_target.scores.zero_() matcher.compare_features_matrix(split=2) assert (matcher.repro_target.indices[:, 0] < 9).all()
def test_indices_symmetry_random(content, style): """The indices of the symmerical operation must be the same. """ matcher1 = FeatureMatcher(content, style) matcher2 = FeatureMatcher(style, content) for _ in range(25): matcher1.compare_features_random() matcher2.compare_features_random() missing = sum( [ (matcher1.repro_target.indices != matcher2.repro_sources.indices).sum(), (matcher1.repro_sources.indices != matcher2.repro_target.indices).sum(), ] ) if missing == 0: break assert (matcher1.repro_target.indices != matcher2.repro_sources.indices).sum() <= 2 assert (matcher1.repro_sources.indices != matcher2.repro_target.indices).sum() <= 2
def test_propagate_down_right(array): """Propagating the identity transformation expects indices to propagate one cell at a time, this time down and towards the right. """ matcher = FeatureMatcher(array, array) indices = matcher.repro_target.indices indices.zero_() matcher.compare_features_nearby(radius=1, split=2) assert (indices[:, :, 1, 0] == torch.tensor([1, 0], dtype=torch.long)).all() assert (indices[:, :, 0, 1] == torch.tensor([0, 1], dtype=torch.long)).all() matcher.compare_features_nearby(radius=1, split=2) assert (indices[:, :, 1, 1] == torch.tensor([1, 1], dtype=torch.long)).all()
def test_scores_source_bias_random(array): matcher = FeatureMatcher(array, torch.cat([array, array], dim=2)) matcher.repro_target.biases[:, :, 8:] = 1.0 matcher.repro_target.scores.fill_(-1.0) for _ in range(10): matcher.compare_features_random(split=2) assert (matcher.repro_target.indices[:, 0] >= 8).all() matcher.repro_target.biases[:, :, 8:] = 0.0 matcher.repro_target.biases[:, :, :8] = 1.0 matcher.repro_target.scores.fill_(-1.0) for _ in range(10): matcher.compare_features_random(split=2) assert (matcher.repro_target.indices[:, 0] < 8).all()
def test_scores_target_bias_random(array): matcher = FeatureMatcher(torch.cat([array, array], dim=2), array) matcher.repro_sources.biases[:, :, 12:] = 1.0 matcher.repro_sources.scores.fill_(-1.0) for _ in range(10): matcher.compare_features_random(split=2) assert (matcher.repro_sources.indices[:, 0] >= 12).all() matcher.repro_sources.biases[:, :, 12:] = 0.0 matcher.repro_sources.biases[:, :, :12] = 1.0 matcher.repro_sources.scores.fill_(-1.0) for _ in range(10): matcher.compare_features_random(split=2) assert (matcher.repro_sources.indices[:, 0] < 12).all()
def test_scores_reconstruct(target, source): """Scores must be one if inputs only vary on one dimension. """ matcher = FeatureMatcher(target, source) matcher.compare_features_matrix() recons_target = matcher.reconstruct_target() score = cosine_similarity_vector_1d(target, recons_target) assert pytest.approx(0.0, abs=1e-6) == abs( score.mean() - matcher.repro_target.scores.mean() ) recons_source = matcher.reconstruct_source() score = cosine_similarity_vector_1d(source, recons_source) assert pytest.approx(0.0, abs=1e-6) == abs( score.mean() - matcher.repro_sources.scores.mean() )