1# Copyright 2018 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Utility methods related to kernelized layers.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21from tensorflow.python.ops import array_ops 22from tensorflow.python.ops import math_ops 23 24 25def _to_matrix(u): 26 """If input tensor is a vector (i.e., has rank 1), converts it to matrix.""" 27 u_rank = len(u.shape) 28 if u_rank not in [1, 2]: 29 raise ValueError('The input tensor should have rank 1 or 2. Given rank: {}' 30 .format(u_rank)) 31 if u_rank == 1: 32 return array_ops.expand_dims(u, 0) 33 return u 34 35 36def _align_matrices(x, y): 37 """Aligns x and y tensors to allow computations over pairs of their rows.""" 38 x_matrix = _to_matrix(x) 39 y_matrix = _to_matrix(y) 40 x_shape = x_matrix.shape 41 y_shape = y_matrix.shape 42 if y_shape[1] != x_shape[1]: # dimensions do not match. 43 raise ValueError( 44 'The outermost dimensions of the input tensors should match. Given: {} ' 45 'vs {}.'.format(y_shape[1], x_shape[1])) 46 47 x_tile = array_ops.tile( 48 array_ops.expand_dims(x_matrix, 1), [1, y_shape[0], 1]) 49 y_tile = array_ops.tile( 50 array_ops.expand_dims(y_matrix, 0), [x_shape[0], 1, 1]) 51 return x_tile, y_tile 52 53 54def inner_product(u, v): 55 u = _to_matrix(u) 56 v = _to_matrix(v) 57 return math_ops.matmul(u, v, transpose_b=True) 58 59 60def exact_gaussian_kernel(x, y, stddev): 61 """Computes exact Gaussian kernel value(s) for tensors x and y and stddev. 62 63 The Gaussian kernel for vectors u, v is defined as follows: 64 K(u, v) = exp(-||u-v||^2 / (2* stddev^2)) 65 where the norm is the l2-norm. x, y can be either vectors or matrices. If they 66 are vectors, they must have the same dimension. If they are matrices, they 67 must have the same number of columns. In the latter case, the method returns 68 (as a matrix) K(u, v) values for all pairs (u, v) where u is a row from x and 69 v is a row from y. 70 71 Args: 72 x: a tensor of rank 1 or 2. It's shape should be either [dim] or [m, dim]. 73 y: a tensor of rank 1 or 2. It's shape should be either [dim] or [n, dim]. 74 stddev: The width of the Gaussian kernel. 75 76 Returns: 77 A single value (scalar) with shape (1, 1) (if x, y are vectors) or a matrix 78 of shape (m, n) with entries K(u, v) (where K is the Gaussian kernel) for 79 all (u,v) pairs where u, v are rows from x and y respectively. 80 81 Raises: 82 InvalidShapeError: if the shapes of x, y are not compatible. 83 """ 84 x_aligned, y_aligned = _align_matrices(x, y) 85 diff_squared_l2_norm = math_ops.reduce_sum( 86 math_ops.squared_difference(x_aligned, y_aligned), 2) 87 return math_ops.exp(-diff_squared_l2_norm / (2 * stddev * stddev)) 88 89 90def exact_laplacian_kernel(x, y, stddev): 91 """Computes exact Laplacian kernel value(s) for tensors x and y using stddev. 92 93 The Laplacian kernel for vectors u, v is defined as follows: 94 K(u, v) = exp(-||u-v|| / stddev) 95 where the norm is the l1-norm. x, y can be either vectors or matrices. If they 96 are vectors, they must have the same dimension. If they are matrices, they 97 must have the same number of columns. In the latter case, the method returns 98 (as a matrix) K(u, v) values for all pairs (u, v) where u is a row from x and 99 v is a row from y. 100 101 Args: 102 x: a tensor of rank 1 or 2. It's shape should be either [dim] or [m, dim]. 103 y: a tensor of rank 1 or 2. It's shape should be either [dim] or [n, dim]. 104 stddev: The width of the Gaussian kernel. 105 106 Returns: 107 A single value (scalar) with shape (1, 1) if x, y are vectors or a matrix 108 of shape (m, n) with entries K(u, v) (where K is the Laplacian kernel) for 109 all (u,v) pairs where u, v are rows from x and y respectively. 110 111 Raises: 112 InvalidShapeError: if the shapes of x, y are not compatible. 113 """ 114 x_aligned, y_aligned = _align_matrices(x, y) 115 diff_l1_norm = math_ops.reduce_sum( 116 math_ops.abs(math_ops.subtract(x_aligned, y_aligned)), 2) 117 return math_ops.exp(-diff_l1_norm / stddev) 118